/** Cast to 64 bit int (assuming double & long long have same endianness), convert from sign-magnitude to 2s-complement, return (magnitude of) difference in ULPs. The difference between 2 64-bit numbers is a 65-bit number, so only get the magnitude of the difference. The usual floating point comparisons (<code>a > b</code>, etc) can be used to find which is bigger. This currently uses isnan and isinf, if they are not defined they should be implemented using bitwise comparisons. isnan must not use <code>x != x</code>, or eqivalent. If no 64bit unsigned int is provided then it becomes very complicated to implement this function. \param a,b Any 64-bit non-denormalised floating point numbers. \return The unsigned distance between <code>a</code> and <code>b</code> in 'floating point space'. */ uint64_t cbf_ULP64(const double a, const double b) { /* Check for NAN or INF, ignore subnormals completely. Don't use 'x!=x' to test for NANs, it might be optimised out, test for a bit pattern manually if 'isnan' or 'isinf' can't be used. */ if (isnan64(a) || isinf64(a) || isnan64(b) || isinf64(b)) { if (isinf64(a) && isinf64(b) && a==b) return 0; return 0xffffffffffffffffl; } else { const uint64_t signmask = 0x8000000000000000l; /* cast numbers so that ia >= ib */ uint64_t ia = *(int64_t*)(a>b ? &a : &b); uint64_t ib = *(int64_t*)(a>b ? &b : &a); /* convert to 2's complement form */ ia = signmask&ia ? signmask^(~ia+1) : ia; ib = signmask&ib ? signmask^(~ib+1) : ib; /* subtract, knowing that ia >= ib */ return ia-ib; } }
_f_int2 _IEEE_EXPONENT_I2_H(_f_real8 x) { int i; REGISTER_8 s1; /* if x is a NaN, return HUGE */ if (isnan64(x)) return(HUGE_INT2_F90); s1.f = x; /* clear sign bit. */ s1.ui &= ~IEEE_64_SIGN_BIT; /* if x is + or minus infinity, return a HUGE */ if (s1.ui == IEEE_64_INFINITY) return(HUGE_INT2_F90); /* if x is zero, return -HUGE */ if (x == 0.0e0) return(-HUGE_INT2_F90); i = __ieee_real4i(x); return ((_f_int2) i); }
/* _IEEE_EXPONENT_I6_R - IEEE EXPONENT returns the exponent part of the * 64-bit argument in 46-bit integer. */ _f_int6 _IEEE_EXPONENT_I6_R(_f_real8 x) { int i; REGISTER_8 s1, s2; /* if x is a NaN, return HUGE */ if (isnan64(x)) return HUGE_INT6_F90; s1.f = x; /* clear sign bit */ s1.ui &= ~IEEE_64_SIGN_BIT; /* if x is + or - infinity, return HUGE */ if (s1.ui == IEEE_64_INFINITY) return HUGE_INT6_F90; /* if x is zero, return -HUGE */ if (x == 0.0e0) return -HUGE_INT6_F90; /* shift exponent bits to right. */ s1.ui >>= IEEE_64_MANT_BITS; if (s1.ui == 0) { /* x is a subnormal number (implicit leading bit is zero * and the exponent is zero). Calculate the exponent * based on normalized x. * * get mantissa */ s2.f = x; s2.ui = IEEE_64_MANTISSA & s2.ui; /* get leading zeros in mantissa part. */ i = _leadz8(s2.ui) - IEEE_64_EXPO_BITS; /* calculate exponent. */ s1.i -= (IEEE_64_EXPO_BIAS + i); } else { /* subtract exponent bias. */ s1.i -= (IEEE_64_EXPO_BIAS); } return (_f_int6) s1.i; }
inline static /* for the inline version of this function. */ #endif _f_real8 _FRACTION(_f_real8 x) { int lz; REGISTER_8 s1, sign_bit, mantissa, exponent; if (x == 0.0) return 0.0; /* if x is either infinity or a NaN, return a Nan */ if (x == IEEE_64_INFINITY) return _SGL_NaN; if (isnan64(x)) return x; s1.f = x; /* get sign bit. */ sign_bit.ui = IEEE_64_SIGN_BIT & s1.ui; /* get mantissa. */ mantissa.ui = IEEE_64_MANTISSA & s1.ui; /* get exponent. */ exponent.ui = IEEE_64_EXPONENT & s1.ui; if (exponent.ui == LL_CONST(0x0)) { /* 1. number is subnormal. normalize mantissa. * Get leading zeros of mantissa. */ lz = _leadz8(mantissa.ui) - IEEE_64_EXPO_BITS; /* 2. normalize by shifting out all leading zeros * and first 1 bit. */ mantissa.ui = (mantissa.ui << lz) & IEEE_64_MANTISSA; } /* position exponent bias less the implicit bit. */ exponent.ui = IEEE_64_EXPO_BIAS - 1; exponent.ui = exponent.ui << IEEE_64_MANT_BITS; /* extract fraction. */ s1.ui = exponent.ui | mantissa.ui | sign_bit.ui; return s1.f; }
_f_real8 _IEEE_BINARY_SCALE_I8(_f_real8 orig_number, _f_int8 orig_scale_factor) { int lz, lzm, shift; REGISTER_8 number, scale_factor, expon, exponent, orig_mantissa, mantissa, sign_bit; /* if x is a NaN, return a Nan */ if (isnan64(orig_number)) return orig_number; number.f = orig_number; /* extract sign bit. */ sign_bit.ui = IEEE_64_SIGN_BIT & number.ui; /* extract exponent. */ exponent.ui = IEEE_64_EXPONENT & number.ui; /* extract mantissa. */ orig_mantissa.ui = IEEE_64_MANTISSA & number.ui; /* if x is + or -infinity, return same infinity */ number.ui &= ~IEEE_64_SIGN_BIT; if (number.ui == IEEE_64_INFINITY) return orig_number; /* if x is zero, return zero. */ if (orig_number == 0) return orig_number; scale_factor.i = orig_scale_factor; /* check for unnormalized number */ if (exponent.ui == 0) { /* Denormmal. Get leading zeros in original mantissa */ lz = _leadz8(orig_mantissa.ui); if (scale_factor.i > 0) { /* Scale number by a positive power of 2. The * result may need to be normalized. Get * leading zeros in mantissa = lzm. */ lzm = lz - IEEE_64_EXPO_BITS - 1; /* Any leading zeros in mantissa? */ if (lzm > 0) { /* check if number of leading zeros in * mantissa allows scaling by shifting. */ if (scale_factor.i <= lzm) { /* Enough lead zeros to shift. * Exponent is unaffected. */ shift = scale_factor.i; expon.i = 0; } else { /* Scale by shifting what we can * and adjust exponent for rest. * The result is a normalized * number. */ shift = lzm + 1; expon.i = scale_factor.i - lzm; } /* No leading zeros in mantissa. */ } else { /* Shift by 1 to normalize mantissa. Do * rest of scaling through exponent. */ shift = 1; expon.i = scale_factor.i; } /* position the exponent. */ exponent.ui = expon.ui << IEEE_64_MANT_BITS; /* scale the mantissa. */ mantissa.ui = orig_mantissa.ui << shift; /* Scale_factor LE 0. */ } else { /* scale mantissa. */ mantissa.ui = orig_mantissa.ui >> (-scale_factor.i); if ((-scale_factor.ui != 0) && (orig_mantissa.ui & (0x1 << (-scale_factor.i - 1)))) { mantissa.ui++; } } /* mask out any bits that may have shifted to the left of * the mantissa area. */ mantissa.ui &= IEEE_64_MANTISSA; /* OR the new mantissa, the new exponent, and the original * sign bit together to create the result. */ number.ui = mantissa.ui | exponent.ui | sign_bit.ui; } else {
_f_real8 _IEEE_REMAINDER_R_R(_f_real8 argx, _f_real8 argy) { /* Union defined to work with IEEE 64-bit floating point. */ union _ieee_double { struct { #if __BYTE_ORDER == __LITTLE_ENDIAN unsigned int mantissa_lo : IEEE_64_MANT_BITS_H2; unsigned int mantissa_up : IEEE_64_MANT_BITS_H1; unsigned int exponent : IEEE_64_EXPO_BITS; unsigned int sign : 1; #else unsigned int sign : 1; unsigned int exponent : IEEE_64_EXPO_BITS; unsigned int mantissa_up : IEEE_64_MANT_BITS_H1; unsigned int mantissa_lo : IEEE_64_MANT_BITS_H2; #endif } parts1; _f_real8 dword; unsigned int lword[2]; unsigned long long llword; long long int64; }; #if __BYTE_ORDER == __LITTLE_ENDIAN const int lword_hi = 1; const int lword_lo = 0; #else const int lword_hi = 0; const int lword_lo = 1; #endif _f_real8 scalet, scaley; unsigned int sign_x = 0X80000000; unsigned int even_x = 0X00000001; union _ieee_double x_val, y_val, tdiv, two_52, evenchk, div_52; union _ieee_double nearint, y_up, y_lo, tdiv_up, tdiv_lo, res; x_val.dword = argx; y_val.dword = argy; two_52.lword[lword_hi] = 0x43300000; /* 2**52 */ two_52.lword[lword_lo] = 0x00000000; div_52.lword[lword_hi] = 0x3CB00000; /* 2**-52 */ div_52.lword[lword_lo] = 0x00000000; /* check input values: x for infinity and y for zero. */ if (((x_val.llword & ~IEEE_64_SIGN_BIT) == IEEE_64_INFINITY) || ((!(isnan64(y_val.dword))) && (y_val.dword == 0.0))) { union _ieee_double x_val; _f_real8 result8; _f_real8 arg8 = 0.0; x_val.llword = _SGL_NaN; /* need to emit invalid exception */ result8 = _raisinvld(arg8, arg8); return(x_val.dword); } tdiv.dword = argx / argy; /* check for 2**52 or greater = already integer */ if ((int) (tdiv.lword[lword_hi] & (~sign_x)) < (int) two_52.lword[lword_hi]) { /* calculate fraction */ evenchk.dword = tdiv.dword - (_f_real8)((_f_int8)tdiv.dword); if (tdiv.dword < 0.0) { nearint.int64 = (_f_int8) (tdiv.dword - 0.5); if ((evenchk.dword == -0.5) && ((nearint.lword[lword_lo] & even_x) != 0)) nearint.int64 += 1; } else { nearint.int64 = (_f_int8) (tdiv.dword + 0.5); if ((evenchk.dword == 0.5) && ((nearint.lword[lword_lo] & even_x) != 0)) nearint.int64 -= 1; } tdiv.dword = (_f_real8) nearint.int64; } /* Calculate upper and lower for y and tdiv. */ y_up.dword = y_val.dword; tdiv_up.dword = tdiv.dword; y_up.parts1.mantissa_lo = 0x0; tdiv_up.parts1.mantissa_lo = 0x0; scalet = 1.0; scaley = 1.0; /* If tdiv_up exponent < 27, scale up to prevent underflow. */ if ((int) tdiv.parts1.exponent < 27) { tdiv_lo.dword = (tdiv.dword * two_52.dword) - (tdiv_up.dword * two_52.dword); scalet = div_52.dword; } else tdiv_lo.dword = tdiv.dword - tdiv_up.dword; /* If y_up exponent < 27, scale up to prevent underflow. */ if ((int) y_val.parts1.exponent < 27) { y_lo.dword = (y_val.dword * two_52.dword) - (y_val.dword * two_52.dword); scaley = div_52.dword; } else y_lo.dword = y_val.dword - y_up.dword; /* algorithm for ieee for x - (x/y)*y. */ res.dword = ((((x_val.dword - (tdiv_up.dword * y_up.dword)) - (scaley * (tdiv_up.dword * y_lo.dword))) - (scalet * (tdiv_lo.dword * y_up.dword))) - (scalet * scaley * (tdiv_lo.dword * y_lo.dword))); if (res.dword == 0.0) res.parts1.sign = x_val.parts1.sign; return(res.dword); }
_f_log8 _IEEE_IS_NAN_L8( _f_real8 x) { /* if x is NaN, return TRUE */ return ((_f_log8) _btol(isnan64(x))); }