Download Reference Manual
The Developer's Library for D
About Wiki Forums Source Search Contact

Changeset 3177

Show
Ignore:
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
  • trunk/tango/math/IEEE.d

    r3173 r3177  
    103103} 
    104104 
     105private: 
    105106/* Most of the functions depend on the format of the largest IEEE floating-point type. 
    106107 * These code will differ depending on whether 'real' is 64, 80, or 128 bits, 
    107108 * 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 * 
    113116 * There is also an unsupported ABI which does not follow IEEE; several of its functions 
    114117 *  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
    116119 */ 
    117120 
    118121version(LittleEndian) { 
    119122    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"); 
    121124} else { 
    122125    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) 
     132static if (real.mant_dig==64 || real.mant_dig==113) 
     133    const ushort EXPMASK = 0x7FFF; 
     134else const ushort EXPMASK = 0x7FF0; 
     135 
     136// POW2MANTDIG = pow(2, real.mant_dig) is the value such that 
     137//  (smallest_denormal)*POW2MANTDIG == real.min 
     138static 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. 
     150version(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 
     172public: 
    125173 
    126174/** IEEE exception status flags 
     
    367415    uint ex; 
    368416 
    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 
    384419    if (ex) { // If exponent is non-zero 
    385420        if (ex == EXPMASK) {   // infinity or NaN 
     
    387422                *vl |= 0xC000000000000000;  // convert $(NAN)S to $(NAN)Q 
    388423                exp = int.min; 
    389             } else if (vu[EXPONENTPOS] & 0x8000) {   // negative infinity 
     424            } else if (vu[EXPONENTPOS_SHORT] & 0x8000) {   // negative infinity 
    390425                exp = int.min; 
    391426            } else {   // positive infinity 
     
    394429        } else { 
    395430            exp = ex - 0x3FFE; 
    396             vu[EXPONENTPOS] = cast(ushort)((0x8000 & vu[EXPONENTPOS]) | 0x3FFE); 
     431            vu[EXPONENTPOS_SHORT] = cast(ushort)((0x8000 & vu[EXPONENTPOS_SHORT]) | 0x3FFE); 
    397432        } 
    398433    } else if (!*vl) { 
     
    407442        } while (*vl > 0); 
    408443        exp = i; 
    409         vu[EXPONENTPOS] = cast(ushort)((0x8000 & vu[EXPONENTPOS]) | 0x3FFE); 
     444        vu[EXPONENTPOS_SHORT] = cast(ushort)((0x8000 & vu[EXPONENTPOS_SHORT]) | 0x3FFE); 
    410445    } 
    411446  } else static if (real.mant_dig == 113) { 
     
    416451                    vl[1] |= 0x0000_8000_0000_0000;  // convert $(NAN)S to $(NAN)Q 
    417452                    exp = int.min; 
    418                 } else if (vu[EXPONENTPOS] & 0x8000) {   // negative infinity 
     453                } else if (vu[EXPONENTPOS_SHORT] & 0x8000) {   // negative infinity 
    419454                    exp = int.min; 
    420455                } else {   // positive infinity 
     
    423458            } else { 
    424459                exp = ex - 0x3FFE; 
    425                 vu[EXPONENTPOS] = cast(ushort)((0x8000 & vu[EXPONENTPOS]) | 0x3FFE); 
     460                vu[EXPONENTPOS_SHORT] = cast(ushort)((0x8000 & vu[EXPONENTPOS_SHORT]) | 0x3FFE); 
    426461            } 
    427462        } else if (*vl==0 && ((vl[1]&0x0000_FFFF_FFFF_FFFF)==0)) { 
     
    439474        } while ((vl[1]&0x0000_8000_0000_0000)== 0); 
    440475        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 
    445479        assert(0, "Unsupported"); 
    446   } else { 
    447     // 64-bit reals 
     480  } else {    // 64-bit reals 
    448481    if (ex) { // If exponent is non-zero 
    449482        if (ex == EXPMASK) {   // infinity or NaN 
     
    458491        } else { 
    459492            exp = (ex - 0x3FE0) >>> 4; 
    460             ve[EXPONENTPOS] = (0x8000 & ve[EXPONENTPOS]) | 0x3FE0; 
     493            ve[EXPONENTPOS_SHORT] = (0x8000 & ve[EXPONENTPOS_SHORT]) | 0x3FE0; 
    461494        } 
    462495    } else if (!(*vl & 0x7FFF_FFFF_FFFF_FFFF)) { 
     
    466499        // denormal 
    467500        ushort sgn; 
    468         sgn = (0x8000 & ve[EXPONENTPOS])| 0x3FE0; 
     501        sgn = (0x8000 & ve[EXPONENTPOS_SHORT])| 0x3FE0; 
    469502        *vl &= 0x7FFF_FFFF_FFFF_FFFF; 
    470503 
     
    475508        } while (*vl > 0); 
    476509        exp = i; 
    477         ve[EXPONENTPOS] = sgn; 
     510        ve[EXPONENTPOS_SHORT] = sgn; 
    478511    } 
    479512  } 
     
    587620            return y; 
    588621        } 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
    590623            if (e == 0x7FFF) { 
    591624                // BUG: should also set the invalid exception 
     
    816849int isNaN(real x) 
    817850{ 
    818   static if (real.mant_dig==double.mant_dig) { 
    819         // 64-bit real 
     851  static if (real.mant_dig==53) { // double 
    820852        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]; 
    832856        ulong*  ps = cast(ulong *)&x; 
    833857        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        } 
    835869  } else { 
    836870      return x!=x; 
     
    860894{ 
    861895    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; 
    866898} 
    867899 
     
    869901int isNormal(double d) 
    870902{ 
    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; 
    876910} 
    877911 
     
    879913int isNormal(real x) 
    880914{ 
    881     static if (real.mant_dig == double.mant_dig) { // double 
     915    static if (real.mant_dig == 53) { // double 
    882916        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]); 
    883920    } 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]; 
    885922        return (e != 0x7FFF && e!=0); 
    886923    } 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]; 
    888925        return (e != 0x7FFF && e!=0); 
    889926    } 
     
    922959    long*   pxs = cast(long *)&x; 
    923960    long*   pys = cast(long *)&y; 
    924   static if (real.mant_dig == double.mant_dig){ //double 
     961  static if (real.mant_dig == 53){ //double 
    925962    return pxs[0] == pys[0]; 
    926963  } else static if (real.mant_dig == 113 || real.mant_dig==106) { 
     
    10061043/// ditto 
    10071044 
    1008 int isSubnormal(real e
    1009 { 
    1010     static if (real.mant_dig == double.mant_dig) { // double 
    1011         return isSubnormal(cast(double)e); 
     1045int isSubnormal(real x
     1046{ 
     1047    static if (real.mant_dig == 53) { // double 
     1048        return isSubnormal(cast(double)x); 
    10121049    } 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)); 
    10161053    } 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; 
    10211058    } 
    10221059} 
     
    10371074int isZero(real x) 
    10381075{ 
    1039     static if (real.mant_dig == double.mant_dig) { 
     1076    static if (real.mant_dig == 53) { // double 
    10401077        return ((*cast(ulong *)&x) & 0x7FFF_FFFF_FFFF_FFFF) == 0; 
    10411078    } else static if (real.mant_dig == 113) { // quadruple    
    10421079        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 
    10451082        ushort* pe = cast(ushort *)&x; 
    10461083        ulong*  ps = cast(ulong  *)&x; 
    1047         return (pe[4] & 0x7FFF) == 0 && *ps == 0; 
     1084        return (pe[EXPONENTPOS_SHORT] & EXPMASK) == 0 && *ps == 0; 
    10481085    } 
    10491086} 
     
    10651102int isInfinity(real x) 
    10661103{ 
    1067     static if (real.mant_dig == double.mant_dig) { 
     1104    static if (real.mant_dig == 53) { // double 
    10681105        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;    
    10691108    } else static if (real.mant_dig == 113) { // quadruple    
    10701109        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; 
    10721112    } else { // real80 
    1073         ushort e = 0x7FFF & (cast(ushort *)&x)[4]; 
     1113        ushort e = EXPMASK & (cast(ushort *)&x)[EXPONENTPOS_SHORT]; 
    10741114        ulong*  ps = cast(ulong *)&x; 
    10751115 
     
    11111151real nextUp(real x) 
    11121152{ 
    1113     static if (real.mant_dig == double.mant_dig) { 
     1153    static if (real.mant_dig == 53) { // double 
    11141154        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; 
    11201159             return x; // +Inf and NaN are unchanged. 
    11211160        }      
    11221161        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; 
    11271166                return x; 
    11281167            } 
    11291168            --*ps; 
    1130             if (*ps==0) --ps[1]; 
     1169            if (ps[MANTISSA_LSB]==0) --ps[MANTISSA_MSB]; 
    11311170        } else { // Positive number 
    1132             ++*ps
    1133             if (*ps==0) ++ps[1]; 
     1171            ++ps[MANTISSA_LSB]
     1172            if (ps[MANTISSA_LSB]==0) ++ps[MANTISSA_MSB]; 
    11341173        } 
    11351174        return x; 
    11361175           
    1137     } else static if(real.mant_dig==64){ 
     1176    } else static if(real.mant_dig==64){ // real80 
    11381177        // For 80-bit reals, the "implied bit" is a nuisance... 
    11391178        ushort *pe = cast(ushort *)&x; 
    11401179        ulong  *ps = cast(ulong  *)&x; 
    11411180 
    1142         if ((pe[4] & 0x7FFF) == 0x7FFF) { 
     1181        if ((pe[EXPONENTPOS_SHORT] & EXPMASK) == 0x7FFF) { 
    11431182            // First, deal with NANs and infinity 
    11441183            if (x == -real.infinity) return -real.max; 
    11451184            return x; // +Inf and NaN are unchanged. 
    11461185        } 
    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 
    11481187            --*ps; 
    11491188            // Need to mask with 0x7FFF... so denormals are treated correctly. 
    11501189            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. 
    11531192                    return x; 
    11541193                } 
    1155                 --pe[4]; 
    1156                 if (pe[4] == 0x8000) { 
     1194                --pe[EXPONENTPOS_SHORT]; 
     1195                if (pe[EXPONENTPOS_SHORT] == 0x8000) { 
    11571196                    return x; // it's become a denormal, implied bit stays low. 
    11581197                } 
     
    11651204            // Works automatically for positive zero. 
    11661205            ++*ps; 
    1167             if ((*ps & 0x7FFFFFFFFFFFFFFF) == 0) { 
     1206            if ((*ps & 0x7FFF_FFFF_FFFF_FFFF) == 0) { 
    11681207                // 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 
    11711210            } 
    11721211        } 
     
    12921331        uint *ps = cast(uint *)&x; 
    12931332        (*ps) &= 0xFFFF_FC00; 
    1294     } else static if (X.mant_dig == double.mant_dig) { 
     1333    } else static if (X.mant_dig == 53) { 
    12951334        ulong *ps = cast(ulong *)&x; 
    12961335        (*ps) &= 0xFFFF_FFFF_FC00_0000; 
     
    13031342    } else static if (X.mant_dig==113) { // quadruple 
    13041343        ulong *ps = cast(ulong *)&x; 
    1305         (*ps) &= 0xFF00_0000_0000_0000;         
     1344        ps[MANTISSA_LSB] &= 0xFF00_0000_0000_0000;         
    13061345    } 
    13071346    //else static assert(0, "Unsupported size"); 
     
    14301469    // they could have 0 or 1 bits in common. 
    14311470 
    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) 
    14441475    {   // Difference is denormal 
    14451476        // For denormals, we need to add the number of zeros that 
     
    14471478        // We do this by multiplying by 2^real.mant_dig 
    14481479        diff *= POW2MANTDIG; 
    1449         return bitsdiff + real.mant_dig - pd[EXPONENTPOS]; 
     1480        return bitsdiff + real.mant_dig - pd[EXPONENTPOS_SHORT]; 
    14501481    } 
    14511482 
     
    14541485 
    14551486    // 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) 
    14671495    {   // Difference is denormal 
    14681496        // For denormals, we need to add the number of zeros that 
    14691497        // lie at the start of diff's significand. 
    14701498        // 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]; 
    14731501    } 
    14741502 
     
    14771505 
    14781506    // 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; 
    14801508    else return 0; 
    14811509 } 
     
    15351563int signbit(real x) 
    15361564{ 
    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; 
    15431566} 
    15441567 
     
    15621585real copysign(real to, real from) 
    15631586{ 
    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; 
    15791593} 
    15801594 
     
    16421656        ulong m = ((*xl) & 0x7FFF_FFFF_FFFF_FFFF) + ((*yl) & 0x7FFF_FFFF_FFFF_FFFF); 
    16431657 
    1644         ushort e = cast(ushort)((xe[4] & 0x7FFF) + (ye[4] & 0x7FFF)); 
     1658        ushort e = cast(ushort)((xe[EXPONENTPOS_SHORT] & 0x7FFF) + (ye[EXPONENTPOS_SHORT] & 0x7FFF)); 
    16451659        if (m & 0x8000_0000_0000_0000) { 
    16461660            ++e; 
     
    16551669        else *ul = m; // ... unless exponent is 0 (denormal or zero). 
    16561670        // 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;            
    16581679    } else static if (T.mant_dig == double.mant_dig) { 
    16591680        ulong *ul = cast(ulong *)&u; 
     
    17111732real NaN(ulong payload) 
    17121733{ 
    1713     static if (real.mant_dig == double.mant_dig) { 
     1734    static if (real.mant_dig == 53) { 
    17141735      ulong v = 2; // no implied bit. quiet bit = 1 
    17151736    } else { 
     
    17341755    a >>=29; 
    17351756 
    1736     static if (real.mant_dig == double.mant_dig) { 
     1757    static if (real.mant_dig == 53) { 
    17371758        v |=0x7FF0_0000_0000_0000; 
    17381759        real x; 
     
    17401761        return x; 
    17411762    } else { 
    1742         // Extended real bits 
    17431763        v <<=11; 
    17441764        a &= 0x7FF; 
    17451765        v |= a; 
    1746  
    17471766        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        } 
    17491778        return x; 
    17501779    } 
     
    17641793{ 
    17651794    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); 
    17681797        // Make it look like an 80-bit significand. 
    17691798        // Skip exponent, and quiet bit 
    17701799        m &= 0x0007_FFFF_FFFF_FFFF; 
    17711800        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); 
    17721810    } 
    17731811    // ignore implicit bit and quiet bit 
     
    17821820unittest { 
    17831821  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) { 
    17851823      assert (getNaNPayload(nan4) == 0x789_ABCD_EF12_3456); 
    17861824  } else {