| 1 |
/* Metafunctions mimicing those in std.math |
|---|
| 2 |
* |
|---|
| 3 |
* Compile with -version=testmeta to run unit tests. |
|---|
| 4 |
*/ |
|---|
| 5 |
module meta.math; |
|---|
| 6 |
|
|---|
| 7 |
/* ******************************************* |
|---|
| 8 |
* bool isnan!(real x) |
|---|
| 9 |
* |
|---|
| 10 |
* Return true if and only if x is an IEEE not-a-number |
|---|
| 11 |
*/ |
|---|
| 12 |
template isnan(real x) |
|---|
| 13 |
{ |
|---|
| 14 |
const bool isnan = (x!<>=0); |
|---|
| 15 |
} |
|---|
| 16 |
|
|---|
| 17 |
template isPositiveZero(real x) |
|---|
| 18 |
{ |
|---|
| 19 |
static if (x==0 && 1.0L/x > 0) |
|---|
| 20 |
const bool isPositiveZero = true; |
|---|
| 21 |
else |
|---|
| 22 |
const bool isPositiveZero = false; |
|---|
| 23 |
} |
|---|
| 24 |
|
|---|
| 25 |
template isNegativeZero(real x) |
|---|
| 26 |
{ |
|---|
| 27 |
static if (x==0 && 1.0L/x < 0) |
|---|
| 28 |
const bool isNegativeZero = true; |
|---|
| 29 |
else |
|---|
| 30 |
const bool isNegativeZero = false; |
|---|
| 31 |
} |
|---|
| 32 |
|
|---|
| 33 |
version(testmeta) { |
|---|
| 34 |
|
|---|
| 35 |
static assert( isPositiveZero!(0.0L)); |
|---|
| 36 |
static assert( !isPositiveZero!(-0.0L)); |
|---|
| 37 |
static assert( !isPositiveZero!(real.nan)); |
|---|
| 38 |
static assert( isNegativeZero!(-0.0L)); |
|---|
| 39 |
static assert( !isNegativeZero!(0.0L)); |
|---|
| 40 |
} |
|---|
| 41 |
|
|---|
| 42 |
/* real abs!(real x) */ |
|---|
| 43 |
template abs(real x) |
|---|
| 44 |
{ |
|---|
| 45 |
static if (x<0) const real abs = -x; |
|---|
| 46 |
else const real abs = x; |
|---|
| 47 |
} |
|---|
| 48 |
|
|---|
| 49 |
/* long abs(long x) */ |
|---|
| 50 |
template abs(long x) |
|---|
| 51 |
{ |
|---|
| 52 |
static if (x<0) const long abs = -x; |
|---|
| 53 |
else const long abs = x; |
|---|
| 54 |
} |
|---|
| 55 |
|
|---|
| 56 |
/* ******************************************* |
|---|
| 57 |
* int binaryExponent!(real x) |
|---|
| 58 |
* Returns the binary exponent of a real number x. |
|---|
| 59 |
* |
|---|
| 60 |
* x must not be infinity or nan. |
|---|
| 61 |
*/ |
|---|
| 62 |
template binaryExponent(real x) |
|---|
| 63 |
{ |
|---|
| 64 |
static if (x<0) const int binaryExponent = .binaryExponent!(-x); |
|---|
| 65 |
else static if (x>0x1p128) const int binaryExponent = .binaryExponent!(x/0x1p128)+ 128; |
|---|
| 66 |
else static if (x<0x1p-128)const int binaryExponent = .binaryExponent!(x*0x1p128)- 128; |
|---|
| 67 |
else static if (x>0x1p32) const int binaryExponent = .binaryExponent!(x/0x1p32)+ 32; |
|---|
| 68 |
else static if (x<0x1p-32) const int binaryExponent = .binaryExponent!(x*0x1p32)- 32; |
|---|
| 69 |
else static if (x>=2.0) const int binaryExponent = .binaryExponent!(x/2) + 1; |
|---|
| 70 |
else static if (x<1.0) const int binaryExponent = .binaryExponent!(x*2) - 1; |
|---|
| 71 |
else const int binaryExponent = 0; |
|---|
| 72 |
} |
|---|
| 73 |
|
|---|
| 74 |
/* ******************************************* |
|---|
| 75 |
* int decimalExponent!(real x) |
|---|
| 76 |
* Returns the decimal exponent of a real number x. |
|---|
| 77 |
* |
|---|
| 78 |
* x must not be infinity or nan. |
|---|
| 79 |
*/ |
|---|
| 80 |
template decimalExponent(real x) |
|---|
| 81 |
{ |
|---|
| 82 |
static if (x<0) const int decimalExponent = .decimalExponent!(-x); |
|---|
| 83 |
else static if (x<1) |
|---|
| 84 |
const int decimalExponent = -1 - .decimalExponent!(1/x); |
|---|
| 85 |
else static if (x>1e10000L) |
|---|
| 86 |
const int decimalExponent= .decimalExponent!(x/1e10000L) + 10000; |
|---|
| 87 |
else static if (x>1e1000L) |
|---|
| 88 |
const int decimalExponent= .decimalExponent!(x/1e1000L) + 1000; |
|---|
| 89 |
else static if (x>1e100L) |
|---|
| 90 |
const int decimalExponent = .decimalExponent!(x/1e100L) + 100; |
|---|
| 91 |
else static if (x>1e10) |
|---|
| 92 |
const int decimalExponent = .decimalExponent!(x/1e10) + 10; |
|---|
| 93 |
else static if (x>10) |
|---|
| 94 |
const int decimalExponent = .decimalExponent!(x/10) + 1; |
|---|
| 95 |
else const int decimalExponent = 0; |
|---|
| 96 |
} |
|---|
| 97 |
|
|---|
| 98 |
/* real binaryMantissa!(real x) */ |
|---|
| 99 |
template binaryMantissa(real x) |
|---|
| 100 |
{ |
|---|
| 101 |
const real binaryMantissa = x * pow!(2, -.binaryExponent!(x)); |
|---|
| 102 |
} |
|---|
| 103 |
|
|---|
| 104 |
/* ******************************************* |
|---|
| 105 |
* real pow!(real a, int b) |
|---|
| 106 |
* Fast integer powers |
|---|
| 107 |
*/ |
|---|
| 108 |
template pow(real a, int b) |
|---|
| 109 |
{ |
|---|
| 110 |
static if (b==0) const real pow=1.0L; |
|---|
| 111 |
else static if (b<0) const real pow = 1.0L/.pow!(a, -b); |
|---|
| 112 |
else static if (b==1) const real pow = a; |
|---|
| 113 |
else static if (b & 1) const real pow = a * .pow!(a*a, b>>1); |
|---|
| 114 |
else const real pow = .pow!(a*a, b>>1); |
|---|
| 115 |
} |
|---|
| 116 |
|
|---|
| 117 |
|
|---|
| 118 |
/* ******************************************* |
|---|
| 119 |
* creal powz!(creal a, int b) |
|---|
| 120 |
* Fast integer powers of a complex number |
|---|
| 121 |
*/ |
|---|
| 122 |
template cpow(creal a, int b) |
|---|
| 123 |
{ |
|---|
| 124 |
static if (b==0) const creal cpow=1.0L; |
|---|
| 125 |
else static if (b<0) const creal cpow = 1.0L/.cpow!(a, -b); |
|---|
| 126 |
else static if (b==1) const creal cpow = a; |
|---|
| 127 |
else static if (b & 1) const creal cpow = a * .cpow!(a*a, b>>1); |
|---|
| 128 |
else const creal cpow = .cpow!(a*a, b>>1); |
|---|
| 129 |
} |
|---|
| 130 |
|
|---|
| 131 |
version(testmeta) { |
|---|
| 132 |
|
|---|
| 133 |
static assert( pow!(22, 13) == 282810057883082752L); |
|---|
| 134 |
static assert( isnan!(real.nan)); |
|---|
| 135 |
static assert(!isnan!(real.infinity)); |
|---|
| 136 |
static assert(binaryExponent!(0x1.54437p+149)==149); |
|---|
| 137 |
static assert(binaryExponent!(0x1.54437p-12)==-12); |
|---|
| 138 |
static assert(binaryExponent!(0x1.54437p0)==0); |
|---|
| 139 |
static assert(decimalExponent!(7e38)==38); |
|---|
| 140 |
static assert(decimalExponent!(7e-38)==-38); |
|---|
| 141 |
static assert(decimalExponent!(1)==0); |
|---|
| 142 |
static assert(decimalExponent!(-300)==2); |
|---|
| 143 |
} |
|---|