 |
Changeset 3177
- Timestamp:
- 02/13/08 06:03:42
(10 months ago)
- Author:
- Don Clugston
- Message:
Refactoring to support both big-endian and little-endian quadruple reals. All functions in math.IEEE are now supported, although none have actually been tested...
-
Files:
-
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
| r3173 |
r3177 |
|
| 103 | 103 | } |
|---|
| 104 | 104 | |
|---|
| | 105 | private: |
|---|
| 105 | 106 | /* Most of the functions depend on the format of the largest IEEE floating-point type. |
|---|
| 106 | 107 | * These code will differ depending on whether 'real' is 64, 80, or 128 bits, |
|---|
| 107 | 108 | * and whether it is a big-endian or little-endian architecture. |
|---|
| 108 | | * Only four 'real' ABIs are currently supported: |
|---|
| 109 | | * 64 bit Big-endian (eg PowerPC) |
|---|
| 110 | | * 64 bit Little-endian |
|---|
| 111 | | * 80 bit Little-endian, with implied bit (eg x87, Itanium). |
|---|
| 112 | | * 128 bit Little-endian (eg SPARC). |
|---|
| | 109 | * Only five 'real' ABIs are currently supported: |
|---|
| | 110 | * 64 bit Big-endian 'double' (eg PowerPC) |
|---|
| | 111 | * 128 bit Big-endian 'quadruple' (eg SPARC) |
|---|
| | 112 | * 64 bit Little-endian 'double' (eg x86-SSE2) |
|---|
| | 113 | * 80 bit Little-endian, with implied bit 'real80' (eg x87, Itanium). |
|---|
| | 114 | * 128 bit Little-endian 'quadruple' (not implemented on any known processor!) |
|---|
| | 115 | * |
|---|
| 113 | 116 | * There is also an unsupported ABI which does not follow IEEE; several of its functions |
|---|
| 114 | 117 | * will generate run-time errors if used. |
|---|
| 115 | | * 128 bit Big-endian (double-double, as used by GDC <= 0.23) |
|---|
| | 118 | * 128 bit Big-endian 'doubledouble' (used by GDC <= 0.23 for PowerPC) |
|---|
| 116 | 119 | */ |
|---|
| 117 | 120 | |
|---|
| 118 | 121 | version(LittleEndian) { |
|---|
| 119 | 122 | static assert(real.mant_dig == 53 || real.mant_dig==64 || real.mant_dig == 113, |
|---|
| 120 | | "Only 64-bit, 80-bit, and 128 reals are supported for LittleEndian CPUs"); |
|---|
| | 123 | "Only 64-bit, 80-bit, and 128-bit reals are supported for LittleEndian CPUs"); |
|---|
| 121 | 124 | } else { |
|---|
| 122 | 125 | static assert(real.mant_dig == 53 || real.mant_dig==106 || real.mant_dig == 113, |
|---|
| 123 | | "Only 64-bit and 128 reals are supported for BigEndian CPUs. 106-bit reals have partial support"); |
|---|
| 124 | | } |
|---|
| | 126 | "Only 64-bit and 128-bit reals are supported for BigEndian CPUs. double-double reals have partial support"); |
|---|
| | 127 | } |
|---|
| | 128 | |
|---|
| | 129 | // We set up constants used for extracting the components of the representation |
|---|
| | 130 | |
|---|
| | 131 | // EXPMASK is a ushort mask to select the exponent portion (without sign) |
|---|
| | 132 | static if (real.mant_dig==64 || real.mant_dig==113) |
|---|
| | 133 | const ushort EXPMASK = 0x7FFF; |
|---|
| | 134 | else const ushort EXPMASK = 0x7FF0; |
|---|
| | 135 | |
|---|
| | 136 | // POW2MANTDIG = pow(2, real.mant_dig) is the value such that |
|---|
| | 137 | // (smallest_denormal)*POW2MANTDIG == real.min |
|---|
| | 138 | static if (real.mant_dig==64) { |
|---|
| | 139 | const real POW2MANTDIG = 0x1p+63; |
|---|
| | 140 | } else static if (real.mant_dig==113){ |
|---|
| | 141 | const real POW2MANTDIG = 0x1p+113; |
|---|
| | 142 | } else static if (real.mant_dig==53) { |
|---|
| | 143 | const real POW2MANTDIG = 0x1p+53; |
|---|
| | 144 | } else static if (real.mant_dig==106) { // double-double |
|---|
| | 145 | const real POW2MANTDIG = 0x1p+53; // doubledouble denormals are strange |
|---|
| | 146 | } |
|---|
| | 147 | |
|---|
| | 148 | // EXPONENTPOS_SHORT is the index of the exponent when represented as a ushort array. |
|---|
| | 149 | // SIGNPOS_BYTE is the index of the sign when represented as a ubyte array. |
|---|
| | 150 | version(LittleEndian) { |
|---|
| | 151 | static if (real.mant_dig==64) { |
|---|
| | 152 | const EXPONENTPOS_SHORT = 4; |
|---|
| | 153 | const SIGNPOS_BYTE = 9; |
|---|
| | 154 | } else static if (real.mant_dig==113) { |
|---|
| | 155 | const EXPONENTPOS_SHORT = 7; |
|---|
| | 156 | const SIGNPOS_BYTE = 15; |
|---|
| | 157 | } else { // static if (real.mant_dig==53) |
|---|
| | 158 | const EXPONENTPOS_SHORT = 3; |
|---|
| | 159 | const SIGNPOS_BYTE = 7; |
|---|
| | 160 | } |
|---|
| | 161 | const MANTISSA_LSB = 0; |
|---|
| | 162 | const MANTISSA_MSB = 1; |
|---|
| | 163 | |
|---|
| | 164 | } else { // BigEndian |
|---|
| | 165 | const EXPONENTPOS_SHORT = 0; |
|---|
| | 166 | const SIGNPOS_BYTE = 0; |
|---|
| | 167 | const MANTISSA_LSB = 1; |
|---|
| | 168 | const MANTISSA_MSB = 0; |
|---|
| | 169 | } |
|---|
| | 170 | |
|---|
| | 171 | |
|---|
| | 172 | public: |
|---|
| 125 | 173 | |
|---|
| 126 | 174 | /** IEEE exception status flags |
|---|
| … | … | |
| 367 | 415 | uint ex; |
|---|
| 368 | 416 | |
|---|
| 369 | | static if (real.mant_dig==64 || real.mant_dig==113) |
|---|
| 370 | | const ushort EXPMASK = 0x7FFF; |
|---|
| 371 | | else const ushort EXPMASK = 0x7FF0; |
|---|
| 372 | | |
|---|
| 373 | | version(LittleEndian) { |
|---|
| 374 | | static if (real.mant_dig==64) const int EXPONENTPOS = 4; |
|---|
| 375 | | else static if (real.mant_dig==113) const int EXPONENTPOS = 7; |
|---|
| 376 | | else const int EXPONENTPOS = 3; |
|---|
| 377 | | } else { // BigEndian |
|---|
| 378 | | const int EXPONENTPOS = 0; |
|---|
| 379 | | } |
|---|
| 380 | | |
|---|
| 381 | | ex = vu[EXPONENTPOS] & EXPMASK; |
|---|
| 382 | | static if (real.mant_dig == 64) { |
|---|
| 383 | | // real is real80 |
|---|
| | 417 | ex = vu[EXPONENTPOS_SHORT] & EXPMASK; |
|---|
| | 418 | static if (real.mant_dig == 64) { // real80 |
|---|
| 384 | 419 | if (ex) { // If exponent is non-zero |
|---|
| 385 | 420 | if (ex == EXPMASK) { // infinity or NaN |
|---|
| … | … | |
| 387 | 422 | *vl |= 0xC000000000000000; // convert $(NAN)S to $(NAN)Q |
|---|
| 388 | 423 | exp = int.min; |
|---|
| 389 | | } else if (vu[EXPONENTPOS] & 0x8000) { // negative infinity |
|---|
| | 424 | } else if (vu[EXPONENTPOS_SHORT] & 0x8000) { // negative infinity |
|---|
| 390 | 425 | exp = int.min; |
|---|
| 391 | 426 | } else { // positive infinity |
|---|
| … | … | |
| 394 | 429 | } else { |
|---|
| 395 | 430 | exp = ex - 0x3FFE; |
|---|
| 396 | | vu[EXPONENTPOS] = cast(ushort)((0x8000 & vu[EXPONENTPOS]) | 0x3FFE); |
|---|
| | 431 | vu[EXPONENTPOS_SHORT] = cast(ushort)((0x8000 & vu[EXPONENTPOS_SHORT]) | 0x3FFE); |
|---|
| 397 | 432 | } |
|---|
| 398 | 433 | } else if (!*vl) { |
|---|
| … | … | |
| 407 | 442 | } while (*vl > 0); |
|---|
| 408 | 443 | exp = i; |
|---|
| 409 | | vu[EXPONENTPOS] = cast(ushort)((0x8000 & vu[EXPONENTPOS]) | 0x3FFE); |
|---|
| | 444 | vu[EXPONENTPOS_SHORT] = cast(ushort)((0x8000 & vu[EXPONENTPOS_SHORT]) | 0x3FFE); |
|---|
| 410 | 445 | } |
|---|
| 411 | 446 | } else static if (real.mant_dig == 113) { |
|---|
| … | … | |
| 416 | 451 | vl[1] |= 0x0000_8000_0000_0000; // convert $(NAN)S to $(NAN)Q |
|---|
| 417 | 452 | exp = int.min; |
|---|
| 418 | | } else if (vu[EXPONENTPOS] & 0x8000) { // negative infinity |
|---|
| | 453 | } else if (vu[EXPONENTPOS_SHORT] & 0x8000) { // negative infinity |
|---|
| 419 | 454 | exp = int.min; |
|---|
| 420 | 455 | } else { // positive infinity |
|---|
| … | … | |
| 423 | 458 | } else { |
|---|
| 424 | 459 | exp = ex - 0x3FFE; |
|---|
| 425 | | vu[EXPONENTPOS] = cast(ushort)((0x8000 & vu[EXPONENTPOS]) | 0x3FFE); |
|---|
| | 460 | vu[EXPONENTPOS_SHORT] = cast(ushort)((0x8000 & vu[EXPONENTPOS_SHORT]) | 0x3FFE); |
|---|
| 426 | 461 | } |
|---|
| 427 | 462 | } else if (*vl==0 && ((vl[1]&0x0000_FFFF_FFFF_FFFF)==0)) { |
|---|
| … | … | |
| 439 | 474 | } while ((vl[1]&0x0000_8000_0000_0000)== 0); |
|---|
| 440 | 475 | exp = i; |
|---|
| 441 | | vu[EXPONENTPOS] = cast(ushort)((0x8000 & vu[EXPONENTPOS]) | 0x3FFE); |
|---|
| 442 | | } |
|---|
| 443 | | } else static if(real.mant_dig==106) { |
|---|
| 444 | | // real is doubledouble |
|---|
| | 476 | vu[EXPONENTPOS_SHORT] = cast(ushort)((0x8000 & vu[EXPONENTPOS_SHORT]) | 0x3FFE); |
|---|
| | 477 | } |
|---|
| | 478 | } else static if(real.mant_dig==106) { // doubledouble |
|---|
| 445 | 479 | assert(0, "Unsupported"); |
|---|
| 446 | | } else { |
|---|
| 447 | | // 64-bit reals |
|---|
| | 480 | } else { // 64-bit reals |
|---|
| 448 | 481 | if (ex) { // If exponent is non-zero |
|---|
| 449 | 482 | if (ex == EXPMASK) { // infinity or NaN |
|---|
| … | … | |
| 458 | 491 | } else { |
|---|
| 459 | 492 | exp = (ex - 0x3FE0) >>> 4; |
|---|
| 460 | | ve[EXPONENTPOS] = (0x8000 & ve[EXPONENTPOS]) | 0x3FE0; |
|---|
| | 493 | ve[EXPONENTPOS_SHORT] = (0x8000 & ve[EXPONENTPOS_SHORT]) | 0x3FE0; |
|---|
| 461 | 494 | } |
|---|
| 462 | 495 | } else if (!(*vl & 0x7FFF_FFFF_FFFF_FFFF)) { |
|---|
| … | … | |
| 466 | 499 | // denormal |
|---|
| 467 | 500 | ushort sgn; |
|---|
| 468 | | sgn = (0x8000 & ve[EXPONENTPOS])| 0x3FE0; |
|---|
| | 501 | sgn = (0x8000 & ve[EXPONENTPOS_SHORT])| 0x3FE0; |
|---|
| 469 | 502 | *vl &= 0x7FFF_FFFF_FFFF_FFFF; |
|---|
| 470 | 503 | |
|---|
| … | … | |
| 475 | 508 | } while (*vl > 0); |
|---|
| 476 | 509 | exp = i; |
|---|
| 477 | | ve[EXPONENTPOS] = sgn; |
|---|
| | 510 | ve[EXPONENTPOS_SHORT] = sgn; |
|---|
| 478 | 511 | } |
|---|
| 479 | 512 | } |
|---|
| … | … | |
| 587 | 620 | return y; |
|---|
| 588 | 621 | } else static if (real.mant_dig==64) { // 80-bit reals |
|---|
| 589 | | short e = (cast(short *)&x)[4] & 0x7FFF; |
|---|
| | 622 | short e = (cast(short *)&x)[4] & EXPMASK; |
|---|
| 590 | 623 | if (e == 0x7FFF) { |
|---|
| 591 | 624 | // BUG: should also set the invalid exception |
|---|
| … | … | |
| 816 | 849 | int isNaN(real x) |
|---|
| 817 | 850 | { |
|---|
| 818 | | static if (real.mant_dig==double.mant_dig) { |
|---|
| 819 | | // 64-bit real |
|---|
| | 851 | static if (real.mant_dig==53) { // double |
|---|
| 820 | 852 | ulong* p = cast(ulong *)&x; |
|---|
| 821 | | return (*p & 0x7FF0_0000 == 0x7FF0_0000) && *p & 0x000F_FFFF; |
|---|
| 822 | | } else static if (real.mant_dig==64) { |
|---|
| 823 | | // real80 |
|---|
| 824 | | ushort e = 0x7FFF & (cast(ushort *)&x)[4]; |
|---|
| 825 | | ulong* ps = cast(ulong *)&x; |
|---|
| 826 | | |
|---|
| 827 | | return e == 0x7FFF && |
|---|
| 828 | | *ps & 0x7FFFFFFFFFFFFFFF; // not infinity |
|---|
| 829 | | } else static if (real.mant_dig==113) { |
|---|
| 830 | | // quadruple |
|---|
| 831 | | ushort e = 0x7FFF & (cast(ushort *)&x)[7]; |
|---|
| | 853 | return (*p & 0x7FF0_0000_0000_0000 == 0x7FF0_0000_0000_0000) && *p & 0x000F_FFFF_FFFF_FFFF; |
|---|
| | 854 | } else static if (real.mant_dig==64) { // real80 |
|---|
| | 855 | ushort e = EXPMASK & (cast(ushort *)&x)[EXPONENTPOS_SHORT]; |
|---|
| 832 | 856 | ulong* ps = cast(ulong *)&x; |
|---|
| 833 | 857 | return e == 0x7FFF && |
|---|
| 834 | | (*ps | (ps[1]& 0x0000_FFFF_FFFF_FFFF))!=0; |
|---|
| | 858 | *ps & 0x7FFF_FFFF_FFFF_FFFF; // not infinity |
|---|
| | 859 | } else static if (real.mant_dig==113) { // quadruple |
|---|
| | 860 | ushort e = EXPMASK & (cast(ushort *)&x)[EXPONENTPOS_SHORT]; |
|---|
| | 861 | ulong* ps = cast(ulong *)&x; |
|---|
| | 862 | version(LittleEndian) { |
|---|
| | 863 | return e == 0x7FFF && |
|---|
| | 864 | (*ps | (ps[1]& 0x0000_FFFF_FFFF_FFFF))!=0; |
|---|
| | 865 | } else { |
|---|
| | 866 | return e == 0x7FFF && |
|---|
| | 867 | (ps[1] | (ps[0]& 0x0000_FFFF_FFFF_FFFF))!=0; |
|---|
| | 868 | } |
|---|
| 835 | 869 | } else { |
|---|
| 836 | 870 | return x!=x; |
|---|
| … | … | |
| 860 | 894 | { |
|---|
| 861 | 895 | uint *p = cast(uint *)&x; |
|---|
| 862 | | uint e; |
|---|
| 863 | | |
|---|
| 864 | | e = *p & 0x7F800000; |
|---|
| 865 | | return e && e != 0x7F800000; |
|---|
| | 896 | uint e = *p & 0x7F80_0000; |
|---|
| | 897 | return e!=0 && e != 0x7F80_0000; |
|---|
| 866 | 898 | } |
|---|
| 867 | 899 | |
|---|
| … | … | |
| 869 | 901 | int isNormal(double d) |
|---|
| 870 | 902 | { |
|---|
| 871 | | uint *p = cast(uint *)&d; |
|---|
| 872 | | uint e; |
|---|
| 873 | | |
|---|
| 874 | | e = p[1] & 0x7FF00000; |
|---|
| 875 | | return e && e != 0x7FF00000; |
|---|
| | 903 | ushort *p = cast(ushort *)&d; |
|---|
| | 904 | version(LittleEndian) { |
|---|
| | 905 | uint e = p[3] & 0x7FF0; |
|---|
| | 906 | } else { |
|---|
| | 907 | uint e = p[0] & 0x7FF0; |
|---|
| | 908 | } |
|---|
| | 909 | return e!=0 && e != 0x7FF0; |
|---|
| 876 | 910 | } |
|---|
| 877 | 911 | |
|---|
| … | … | |
| 879 | 913 | int isNormal(real x) |
|---|
| 880 | 914 | { |
|---|
| 881 | | static if (real.mant_dig == double.mant_dig) { // double |
|---|
| | 915 | static if (real.mant_dig == 53) { // double |
|---|
| 882 | 916 | return isNormal(cast(double)x); |
|---|
| | 917 | } else static if(real.mant_dig==106) { // doubledouble |
|---|
| | 918 | // doubledouble is normal if the least significant part is normal. |
|---|
| | 919 | return isNormal((cast(double*)&x)[1]); |
|---|
| 883 | 920 | } else static if (real.mant_dig == 64) { // real80 |
|---|
| 884 | | ushort e = 0x7FFF & (cast(ushort *)&x)[4]; |
|---|
| | 921 | ushort e = EXPMASK & (cast(ushort *)&x)[EXPONENTPOS_SHORT]; |
|---|
| 885 | 922 | return (e != 0x7FFF && e!=0); |
|---|
| 886 | 923 | } else static if (real.mant_dig == 113) { // quadruple |
|---|
| 887 | | ushort e = 0x7FFF & (cast(ushort *)&x)[7]; |
|---|
| | 924 | ushort e = EXPMASK & (cast(ushort *)&x)[EXPONENTPOS_SHORT]; |
|---|
| 888 | 925 | return (e != 0x7FFF && e!=0); |
|---|
| 889 | 926 | } |
|---|
| … | … | |
| 922 | 959 | long* pxs = cast(long *)&x; |
|---|
| 923 | 960 | long* pys = cast(long *)&y; |
|---|
| 924 | | static if (real.mant_dig == double.mant_dig){ //double |
|---|
| | 961 | static if (real.mant_dig == 53){ //double |
|---|
| 925 | 962 | return pxs[0] == pys[0]; |
|---|
| 926 | 963 | } else static if (real.mant_dig == 113 || real.mant_dig==106) { |
|---|
| … | … | |
| 1006 | 1043 | /// ditto |
|---|
| 1007 | 1044 | |
|---|
| 1008 | | int isSubnormal(real e) |
|---|
| 1009 | | { |
|---|
| 1010 | | static if (real.mant_dig == double.mant_dig) { // double |
|---|
| 1011 | | return isSubnormal(cast(double)e); |
|---|
| | 1045 | int isSubnormal(real x) |
|---|
| | 1046 | { |
|---|
| | 1047 | static if (real.mant_dig == 53) { // double |
|---|
| | 1048 | return isSubnormal(cast(double)x); |
|---|
| 1012 | 1049 | } else static if (real.mant_dig == 113) { // quadruple |
|---|
| 1013 | | ushort e = 0x7FFF & (cast(ushort *)&x)[7]; |
|---|
| 1014 | | long* ps = cast(long *)&e; |
|---|
| 1015 | | return (e == 0 && (ps[0]!=0 || (ps[1]& 0x0000_FFFF_FFFF_FFFF) !=0)); |
|---|
| | 1050 | ushort e = EXPMASK & (cast(ushort *)&x)[EXPONENTPOS_SHORT]; |
|---|
| | 1051 | long* ps = cast(long *)&x; |
|---|
| | 1052 | return (e == 0 && (((ps[MANTISSA_LSB]|(ps[MANTISSA_MSB]& 0x0000_FFFF_FFFF_FFFF))) !=0)); |
|---|
| 1016 | 1053 | } else { // real80 |
|---|
| 1017 | | ushort* pe = cast(ushort *)&e; |
|---|
| 1018 | | long* ps = cast(long *)&e; |
|---|
| 1019 | | |
|---|
| 1020 | | return (pe[4] & 0x7FFF) == 0 && *ps > 0; |
|---|
| | 1054 | ushort* pe = cast(ushort *)&x; |
|---|
| | 1055 | long* ps = cast(long *)&x; |
|---|
| | 1056 | |
|---|
| | 1057 | return (pe[EXPONENTPOS_SHORT] & EXPMASK) == 0 && *ps > 0; |
|---|
| 1021 | 1058 | } |
|---|
| 1022 | 1059 | } |
|---|
| … | … | |
| 1037 | 1074 | int isZero(real x) |
|---|
| 1038 | 1075 | { |
|---|
| 1039 | | static if (real.mant_dig == double.mant_dig) { |
|---|
| | 1076 | static if (real.mant_dig == 53) { // double |
|---|
| 1040 | 1077 | return ((*cast(ulong *)&x) & 0x7FFF_FFFF_FFFF_FFFF) == 0; |
|---|
| 1041 | 1078 | } else static if (real.mant_dig == 113) { // quadruple |
|---|
| 1042 | 1079 | long* ps = cast(long *)&e; |
|---|
| 1043 | | return (ps[0]==0 || (ps[1]& 0x7FFF_FFFF_FFFF_FFFF) == 0); |
|---|
| 1044 | | } else { |
|---|
| | 1080 | return (ps[MANTISSA_LSB]==0 || (ps[MANTISSA_MSB]& 0x7FFF_FFFF_FFFF_FFFF) == 0); |
|---|
| | 1081 | } else { // real80 |
|---|
| 1045 | 1082 | ushort* pe = cast(ushort *)&x; |
|---|
| 1046 | 1083 | ulong* ps = cast(ulong *)&x; |
|---|
| 1047 | | return (pe[4] & 0x7FFF) == 0 && *ps == 0; |
|---|
| | 1084 | return (pe[EXPONENTPOS_SHORT] & EXPMASK) == 0 && *ps == 0; |
|---|
| 1048 | 1085 | } |
|---|
| 1049 | 1086 | } |
|---|
| … | … | |
| 1065 | 1102 | int isInfinity(real x) |
|---|
| 1066 | 1103 | { |
|---|
| 1067 | | static if (real.mant_dig == double.mant_dig) { |
|---|
| | 1104 | static if (real.mant_dig == 53) { // double |
|---|
| 1068 | 1105 | return ((*cast(ulong *)&x)&0x7FFF_FFFF_FFFF_FFFF) == 0x7FF8_0000_0000_0000; |
|---|
| | 1106 | } else static if(real.mant_dig == 106) { //doubledouble |
|---|
| | 1107 | return (((cast(ulong *)&x)[MANTISSA_MSB])&0x7FFF_FFFF_FFFF_FFFF) == 0x7FF8_0000_0000_0000; |
|---|
| 1069 | 1108 | } else static if (real.mant_dig == 113) { // quadruple |
|---|
| 1070 | 1109 | long* ps = cast(long *)&x; |
|---|
| 1071 | | return ps[0]==0 && (ps[1] & 0x7FFF_FFFF_FFFF_FFFF) == 0x7FFF_0000_0000_0000; |
|---|
| | 1110 | return ps[MANTISSA_LSB]==0 |
|---|
| | 1111 | && (ps[MANTISSA_MSB] & 0x7FFF_FFFF_FFFF_FFFF) == 0x7FFF_0000_0000_0000; |
|---|
| 1072 | 1112 | } else { // real80 |
|---|
| 1073 | | ushort e = 0x7FFF & (cast(ushort *)&x)[4]; |
|---|
| | 1113 | ushort e = EXPMASK & (cast(ushort *)&x)[EXPONENTPOS_SHORT]; |
|---|
| 1074 | 1114 | ulong* ps = cast(ulong *)&x; |
|---|
| 1075 | 1115 | |
|---|
| … | … | |
| 1111 | 1151 | real nextUp(real x) |
|---|
| 1112 | 1152 | { |
|---|
| 1113 | | static if (real.mant_dig == double.mant_dig) { |
|---|
| | 1153 | static if (real.mant_dig == 53) { // double |
|---|
| 1114 | 1154 | return nextDoubleUp(x); |
|---|
| 1115 | | } else static if(real.mant_dig==113) { |
|---|
| 1116 | | // quadruple |
|---|
| 1117 | | ushort e = 0x7FFF & (cast(ushort *)&x)[7]; |
|---|
| 1118 | | if (e==0x7FFF) { // NaN or Infinity |
|---|
| 1119 | | if (x==-real.infinity) return -real.max; |
|---|
| | 1155 | } else static if(real.mant_dig==113) { // quadruple |
|---|
| | 1156 | ushort e = EXPMASK & (cast(ushort *)&x)[EXPONENTPOS_SHORT]; |
|---|
| | 1157 | if (e == 0x7FFF) { // NaN or Infinity |
|---|
| | 1158 | if (x == -real.infinity) return -real.max; |
|---|
| 1120 | 1159 | return x; // +Inf and NaN are unchanged. |
|---|
| 1121 | 1160 | } |
|---|
| 1122 | 1161 | ulong* ps = cast(ulong *)&e; |
|---|
| 1123 | | if (ps[1] & 0x8000_0000_0000_0000) { // Negative number |
|---|
| 1124 | | if (ps[0]==0 && ps[1] == 0x8000_0000_0000_0000) { // it was negative zero |
|---|
| 1125 | | *ps = 0x0000_0000_0000_0001; // change to smallest subnormal |
|---|
| 1126 | | ps[1] = 0; |
|---|
| | 1162 | if (ps[MANTISSA_LSB] & 0x8000_0000_0000_0000) { // Negative number |
|---|
| | 1163 | if (ps[MANTISSA_LSB]==0 && ps[MANTISSA_MSB] == 0x8000_0000_0000_0000) { // it was negative zero |
|---|
| | 1164 | ps[MANTISSA_LSB] = 0x0000_0000_0000_0001; // change to smallest subnormal |
|---|
| | 1165 | ps[MANTISSA_MSB] = 0; |
|---|
| 1127 | 1166 | return x; |
|---|
| 1128 | 1167 | } |
|---|
| 1129 | 1168 | --*ps; |
|---|
| 1130 | | if (*ps==0) --ps[1]; |
|---|
| | 1169 | if (ps[MANTISSA_LSB]==0) --ps[MANTISSA_MSB]; |
|---|
| 1131 | 1170 | } else { // Positive number |
|---|
| 1132 | | ++*ps; |
|---|
| 1133 | | if (*ps==0) ++ps[1]; |
|---|
| | 1171 | ++ps[MANTISSA_LSB]; |
|---|
| | 1172 | if (ps[MANTISSA_LSB]==0) ++ps[MANTISSA_MSB]; |
|---|
| 1134 | 1173 | } |
|---|
| 1135 | 1174 | return x; |
|---|
| 1136 | 1175 | |
|---|
| 1137 | | } else static if(real.mant_dig==64){ |
|---|
| | 1176 | } else static if(real.mant_dig==64){ // real80 |
|---|
| 1138 | 1177 | // For 80-bit reals, the "implied bit" is a nuisance... |
|---|
| 1139 | 1178 | ushort *pe = cast(ushort *)&x; |
|---|
| 1140 | 1179 | ulong *ps = cast(ulong *)&x; |
|---|
| 1141 | 1180 | |
|---|
| 1142 | | if ((pe[4] & 0x7FFF) == 0x7FFF) { |
|---|
| | 1181 | if ((pe[EXPONENTPOS_SHORT] & EXPMASK) == 0x7FFF) { |
|---|
| 1143 | 1182 | // First, deal with NANs and infinity |
|---|
| 1144 | 1183 | if (x == -real.infinity) return -real.max; |
|---|
| 1145 | 1184 | return x; // +Inf and NaN are unchanged. |
|---|
| 1146 | 1185 | } |
|---|
| 1147 | | if (pe[4] & 0x8000) { // Negative number -- need to decrease the significand |
|---|
| | 1186 | if (pe[EXPONENTPOS_SHORT] & 0x8000) { // Negative number -- need to decrease the significand |
|---|
| 1148 | 1187 | --*ps; |
|---|
| 1149 | 1188 | // Need to mask with 0x7FFF... so denormals are treated correctly. |
|---|
| 1150 | 1189 | if ((*ps & 0x7FFFFFFFFFFFFFFF) == 0x7FFFFFFFFFFFFFFF) { |
|---|
| 1151 | | if (pe[4] == 0x8000) { // it was negative zero |
|---|
| 1152 | | *ps = 1; pe[4] = 0; // smallest subnormal. |
|---|
| | 1190 | if (pe[EXPONENTPOS_SHORT] == 0x8000) { // it was negative zero |
|---|
| | 1191 | *ps = 1; pe[EXPONENTPOS_SHORT] = 0; // smallest subnormal. |
|---|
| 1153 | 1192 | return x; |
|---|
| 1154 | 1193 | } |
|---|
| 1155 | | --pe[4]; |
|---|
| 1156 | | if (pe[4] == 0x8000) { |
|---|
| | 1194 | --pe[EXPONENTPOS_SHORT]; |
|---|
| | 1195 | if (pe[EXPONENTPOS_SHORT] == 0x8000) { |
|---|
| 1157 | 1196 | return x; // it's become a denormal, implied bit stays low. |
|---|
| 1158 | 1197 | } |
|---|
| … | … | |
| 1165 | 1204 | // Works automatically for positive zero. |
|---|
| 1166 | 1205 | ++*ps; |
|---|
| 1167 | | if ((*ps & 0x7FFFFFFFFFFFFFFF) == 0) { |
|---|
| | 1206 | if ((*ps & 0x7FFF_FFFF_FFFF_FFFF) == 0) { |
|---|
| 1168 | 1207 | // change in exponent |
|---|
| 1169 | | ++pe[4]; |
|---|
| 1170 | | *ps = 0x8000000000000000; // set the high bit |
|---|
| | 1208 | ++pe[EXPONENTPOS_SHORT]; |
|---|
| | 1209 | *ps = 0x8000_0000_0000_0000; // set the high bit |
|---|
| 1171 | 1210 | } |
|---|
| 1172 | 1211 | } |
|---|
| … | … | |
| 1292 | 1331 | uint *ps = cast(uint *)&x; |
|---|
| 1293 | 1332 | (*ps) &= 0xFFFF_FC00; |
|---|
| 1294 | | } else static if (X.mant_dig == double.mant_dig) { |
|---|
| | 1333 | } else static if (X.mant_dig == 53) { |
|---|
| 1295 | 1334 | ulong *ps = cast(ulong *)&x; |
|---|
| 1296 | 1335 | (*ps) &= 0xFFFF_FFFF_FC00_0000; |
|---|
| … | … | |
| 1303 | 1342 | } else static if (X.mant_dig==113) { // quadruple |
|---|
| 1304 | 1343 | ulong *ps = cast(ulong *)&x; |
|---|
| 1305 | | (*ps) &= 0xFF00_0000_0000_0000; |
|---|
| | 1344 | ps[MANTISSA_LSB] &= 0xFF00_0000_0000_0000; |
|---|
| 1306 | 1345 | } |
|---|
| 1307 | 1346 | //else static assert(0, "Unsupported size"); |
|---|
| … | … | |
| 1430 | 1469 | // they could have 0 or 1 bits in common. |
|---|
| 1431 | 1470 | |
|---|
| 1432 | | static if (real.mant_dig==64 || real.mant_dig==113) { |
|---|
| 1433 | | static if (real.mant_dig==64) { |
|---|
| 1434 | | const int EXPONENTPOS = 4; |
|---|
| 1435 | | const real POW2MANTDIG = 0x1p+63; |
|---|
| 1436 | | } else { |
|---|
| 1437 | | const int EXPONENTPOS = 7; |
|---|
| 1438 | | const real POW2MANTDIG = 0x1p+113; |
|---|
| 1439 | | } |
|---|
| 1440 | | |
|---|
| 1441 | | int bitsdiff = ( ((pa[EXPONENTPOS]&0x7FFF) + (pb[EXPONENTPOS]&0x7FFF)-1)>>1) - pd[EXPONENTPOS]; |
|---|
| 1442 | | |
|---|
| 1443 | | if (pd[EXPONENTPOS] == 0) |
|---|
| | 1471 | static if (real.mant_dig==64 || real.mant_dig==113) { // real64 |
|---|
| | 1472 | int bitsdiff = ( ((pa[EXPONENTPOS_SHORT]&0x7FFF) + (pb[EXPONENTPOS_SHORT]&0x7FFF)-1)>>1) - pd[EXPONENTPOS_SHORT]; |
|---|
| | 1473 | |
|---|
| | 1474 | if (pd[EXPONENTPOS_SHORT] == 0) |
|---|
| 1444 | 1475 | { // Difference is denormal |
|---|
| 1445 | 1476 | // For denormals, we need to add the number of zeros that |
|---|
| … | … | |
| 1447 | 1478 | // We do this by multiplying by 2^real.mant_dig |
|---|
| 1448 | 1479 | diff *= POW2MANTDIG; |
|---|
| 1449 | | return bitsdiff + real.mant_dig - pd[EXPONENTPOS]; |
|---|
| | 1480 | return bitsdiff + real.mant_dig - pd[EXPONENTPOS_SHORT]; |
|---|
| 1450 | 1481 | } |
|---|
| 1451 | 1482 | |
|---|
| … | … | |
| 1454 | 1485 | |
|---|
| 1455 | 1486 | // Avoid out-by-1 errors when factor is almost 2. |
|---|
| 1456 | | return (bitsdiff == 0) ? (pa[EXPONENTPOS] == pb[EXPONENTPOS]) : 0; |
|---|
| 1457 | | } else { |
|---|
| 1458 | | // 64-bit reals |
|---|
| 1459 | | version(LittleEndian) |
|---|
| 1460 | | const int EXPONENTPOS = 3; |
|---|
| 1461 | | else const int EXPONENTPOS = 0; |
|---|
| 1462 | | |
|---|
| 1463 | | int bitsdiff = (( ((pa[EXPONENTPOS]&0x7FF0) + (pb[EXPONENTPOS]&0x7FF0)-0x10)>>1) |
|---|
| 1464 | | - (pd[EXPONENTPOS]&0x7FF0))>>4; |
|---|
| 1465 | | |
|---|
| 1466 | | if (pd[EXPONENTPOS] == 0) |
|---|
| | 1487 | return (bitsdiff == 0) ? (pa[EXPONENTPOS_SHORT] == pb[EXPONENTPOS_SHORT]) : 0; |
|---|
| | 1488 | } else static if(real.mant_dig==106) { // doubledouble |
|---|
| | 1489 | assert(0, "Unsupported"); |
|---|
| | 1490 | } else { // real64 |
|---|
| | 1491 | int bitsdiff = (( ((pa[EXPONENTPOS_SHORT]&0x7FF0) + (pb[EXPONENTPOS_SHORT]&0x7FF0)-0x10)>>1) |
|---|
| | 1492 | - (pd[EXPONENTPOS_SHORT]&0x7FF0))>>4; |
|---|
| | 1493 | |
|---|
| | 1494 | if (pd[EXPONENTPOS_SHORT] == 0) |
|---|
| 1467 | 1495 | { // Difference is denormal |
|---|
| 1468 | 1496 | // For denormals, we need to add the number of zeros that |
|---|
| 1469 | 1497 | // lie at the start of diff's significand. |
|---|
| 1470 | 1498 | // We do this by multiplying by 2^real.mant_dig |
|---|
| 1471 | | diff *= 0x1p+53; |
|---|
| 1472 | | return bitsdiff + real.mant_dig - pd[EXPONENTPOS]; |
|---|
| | 1499 | diff *= POW2MANTDIG; |
|---|
| | 1500 | return bitsdiff + real.mant_dig - pd[EXPONENTPOS_SHORT]; |
|---|
| 1473 | 1501 | } |
|---|
| 1474 | 1502 | |
|---|
| … | … | |
| 1477 | 1505 | |
|---|
| 1478 | 1506 | // Avoid out-by-1 errors when factor is almost 2. |
|---|
| 1479 | | if (bitsdiff == 0 && !((pa[EXPONENTPOS] ^ pb[EXPONENTPOS])&0x7FF0)) return 1; |
|---|
| | 1507 | if (bitsdiff == 0 && !((pa[EXPONENTPOS_SHORT] ^ pb[EXPONENTPOS_SHORT])&EXPMASK)) return 1; |
|---|
| 1480 | 1508 | else return 0; |
|---|
| 1481 | 1509 | } |
|---|
| … | … | |
| 1535 | 1563 | int signbit(real x) |
|---|
| 1536 | 1564 | { |
|---|
| 1537 | | static if (real.mant_dig == double.mant_dig) { |
|---|
| 1538 | | return ((*cast(ulong *)&x) & 0x8000_0000_0000_0000) != 0; |
|---|
| 1539 | | } else { |
|---|
| 1540 | | ubyte* pe = cast(ubyte *)&x; |
|---|
| 1541 | | return (pe[9] & 0x80) != 0; |
|---|
| 1542 | | } |
|---|
| | 1565 | return ((cast(ubyte *)&x)[SIGNPOS_BYTE] & 0x80) != 0; |
|---|
| 1543 | 1566 | } |
|---|
| 1544 | 1567 | |
|---|
| … | … | |
| 1562 | 1585 | real copysign(real to, real from) |
|---|
| 1563 | 1586 | { |
|---|
| 1564 | | static if (real.mant_dig == double.mant_dig) { |
|---|
| 1565 | | ulong* pto = cast(ulong *)&to; |
|---|
| 1566 | | ulong* pfrom = cast(ulong *)&from; |
|---|
| 1567 | | *pto &= 0x7FFF_FFFF_FFFF_FFFF; |
|---|
| 1568 | | *pto |= (*pfrom) & 0x8000_0000_0000_0000; |
|---|
| 1569 | | return to; |
|---|
| 1570 | | } else { |
|---|
| 1571 | | ubyte* pto = cast(ubyte *)&to; |
|---|
| 1572 | | ubyte* pfrom = cast(ubyte *)&from; |
|---|
| 1573 | | |
|---|
| 1574 | | pto[9] &= 0x7F; |
|---|
| 1575 | | pto[9] |= pfrom[9] & 0x80; |
|---|
| 1576 | | |
|---|
| 1577 | | return to; |
|---|
| 1578 | | } |
|---|
| | 1587 | ubyte* pto = cast(ubyte *)&to; |
|---|
| | 1588 | ubyte* pfrom = cast(ubyte *)&from; |
|---|
| | 1589 | |
|---|
| | 1590 | pto[SIGNPOS_BYTE] &= 0x7F; |
|---|
| | 1591 | pto[SIGNPOS_BYTE] |= pfrom[SIGNPOS_BYTE] & 0x80; |
|---|
| | 1592 | return to; |
|---|
| 1579 | 1593 | } |
|---|
| 1580 | 1594 | |
|---|
| … | … | |
| 1642 | 1656 | ulong m = ((*xl) & 0x7FFF_FFFF_FFFF_FFFF) + ((*yl) & 0x7FFF_FFFF_FFFF_FFFF); |
|---|
| 1643 | 1657 | |
|---|
| 1644 | | ushort e = cast(ushort)((xe[4] & 0x7FFF) + (ye[4] & 0x7FFF)); |
|---|
| | 1658 | ushort e = cast(ushort)((xe[EXPONENTPOS_SHORT] & 0x7FFF) + (ye[EXPONENTPOS_SHORT] & 0x7FFF)); |
|---|
| 1645 | 1659 | if (m & 0x8000_0000_0000_0000) { |
|---|
| 1646 | 1660 | ++e; |
|---|
| … | … | |
| 1655 | 1669 | else *ul = m; // ... unless exponent is 0 (denormal or zero). |
|---|
| 1656 | 1670 | // Prevent a ridiculous warning (why does (ushort | ushort) get promoted to int???) |
|---|
| 1657 | | ue[4]= cast(ushort)( e | (xe[4]& 0x8000)); // restore sign bit |
|---|
| | 1671 | ue[4]= cast(ushort)( e | (xe[EXPONENTPOS_SHORT]& 0x8000)); // restore sign bit |
|---|
| | 1672 | } else static if(T.mant_dig == 113) { //quadruple |
|---|
| | 1673 | ulong *ul = cast(ulong *)&u; |
|---|
| | 1674 | ulong *xl = cast(ulong *)&x; |
|---|
| | 1675 | ulong *yl = cast(ulong *)&y; |
|---|
| | 1676 | ulong m = (((*xl) & 0x7FFF_FFFF_FFFF_FFFF) + ((*yl) & 0x7FFF_FFFF_FFFF_FFFF)) >>> 1; |
|---|
| | 1677 | m |= ((*xl) & 0x8000_0000_0000_0000); |
|---|
| | 1678 | *ul = m; |
|---|
| 1658 | 1679 | } else static if (T.mant_dig == double.mant_dig) { |
|---|
| 1659 | 1680 | ulong *ul = cast(ulong *)&u; |
|---|
| … | … | |
| 1711 | 1732 | real NaN(ulong payload) |
|---|
| 1712 | 1733 | { |
|---|
| 1713 | | static if (real.mant_dig == double.mant_dig) { |
|---|
| | 1734 | static if (real.mant_dig == 53) { |
|---|
| 1714 | 1735 | ulong v = 2; // no implied bit. quiet bit = 1 |
|---|
| 1715 | 1736 | } else { |
|---|
| … | … | |
| 1734 | 1755 | a >>=29; |
|---|
| 1735 | 1756 | |
|---|
| 1736 | | static if (real.mant_dig == double.mant_dig) { |
|---|
| | 1757 | static if (real.mant_dig == 53) { |
|---|
| 1737 | 1758 | v |=0x7FF0_0000_0000_0000; |
|---|
| 1738 | 1759 | real x; |
|---|
| … | … | |
| 1740 | 1761 | return x; |
|---|
| 1741 | 1762 | } else { |
|---|
| 1742 | | // Extended real bits |
|---|
| 1743 | 1763 | v <<=11; |
|---|
| 1744 | 1764 | a &= 0x7FF; |
|---|
| 1745 | 1765 | v |= a; |
|---|
| 1746 | | |
|---|
| 1747 | 1766 | real x = real.nan; |
|---|
| 1748 | | * cast(ulong *)(&x) = v; |
|---|
| | 1767 | // Extended real bits |
|---|
| | 1768 | static if (real.mant_dig==113) { //quadruple |
|---|
| | 1769 | v<<=1; // there's no implicit bit |
|---|
| | 1770 | version(LittleEndian) { |
|---|
| | 1771 | *cast(ulong*)(6+cast(ubyte*)(&x)) = v; |
|---|
| | 1772 | } else { |
|---|
| | 1773 | *cast(ulong*)(2+cast(ubyte*)(&x)) = v; |
|---|
| | 1774 | } |
|---|
| | 1775 | } else { // real80 |
|---|
| | 1776 | * cast(ulong *)(&x) = v; |
|---|
| | 1777 | } |
|---|
| 1749 | 1778 | return x; |
|---|
| 1750 | 1779 | } |
|---|
| … | … | |
| 1764 | 1793 | { |
|---|
| 1765 | 1794 | assert(isNaN(x)); |
|---|
| 1766 | | ulong m = *cast(ulong *)(&x); |
|---|
| 1767 | | static if (real.mant_dig == double.mant_dig) { |
|---|
| | 1795 | static if (real.mant_dig == 53) { |
|---|
| | 1796 | ulong m = *cast(ulong *)(&x); |
|---|
| 1768 | 1797 | // Make it look like an 80-bit significand. |
|---|
| 1769 | 1798 | // Skip exponent, and quiet bit |
|---|
| 1770 | 1799 | m &= 0x0007_FFFF_FFFF_FFFF; |
|---|
| 1771 | 1800 | m <<= 10; |
|---|
| | 1801 | } else static if (real.mant_dig==113) { // quadruple |
|---|
| | 1802 | version(LittleEndian) { |
|---|
| | 1803 | ulong m = *cast(ulong*)(6+cast(ubyte*)(&x)); |
|---|
| | 1804 | } else { |
|---|
| | 1805 | ulong m = *cast(ulong*)(2+cast(ubyte*)(&x)); |
|---|
| | 1806 | } |
|---|
| | 1807 | m>>=1; // there's no implicit bit |
|---|
| | 1808 | } else { |
|---|
| | 1809 | ulong m = *cast(ulong *)(&x); |
|---|
| 1772 | 1810 | } |
|---|
| 1773 | 1811 | // ignore implicit bit and quiet bit |
|---|
| … | … | |
| 1782 | 1820 | unittest { |
|---|
| 1783 | 1821 | real nan4 = NaN(0x789_ABCD_EF12_3456); |
|---|
| 1784 | | static if (real.mant_dig == 64) { |
|---|
| | 1822 | static if (real.mant_dig == 64 || real.mant_dig==113) { |
|---|
| 1785 | 1823 | assert (getNaNPayload(nan4) == 0x789_ABCD_EF12_3456); |
|---|
| 1786 | 1824 | } else { |
|---|
Download in other formats:
|
 |
 |
|
 |
Copyright © 2006-2008 Tango. All Rights Reserved. | Page Width:
Static or
Dynamic