this repo has no description
at fixPythonPipStalling 172 lines 3.5 kB view raw
1/* 2 * remainder.c 3 * cLibm 4 * 5 * Written by Jon Okada, started on December 7th, 1992. 6 * Modified by Paul Finlayson (PAF) for MathLib v2. 7 * Modified by A. Sazegari (ali) for MathLib v3. 8 * Modified and ported by Robert A. Murley (ram) for Mac OS X. 9 * Modified for cLibm, fixed a few edge cases, rewrote local_ funcs by Ian Ollmann. 10 * 11 * Copyright 2007 Apple Inc. All rights reserved. 12 * 13 */ 14 15 #include <math.h> 16 #include <float.h> 17 #include <stdint.h> 18 19#ifdef ARMLIBM_SET_FLAGS 20 #include "required_arithmetic.h" 21#endif 22 23static inline int local_ilogb( double x ) __attribute__ ((always_inline)); 24static inline int local_ilogb( double x ) 25{ 26 union{ double d; uint64_t u;}u = {x}; 27 28 u.u &= 0x7fffffffffffffffULL; 29 int32_t exp = (int32_t) (u.u >> 52); 30 31 if( __builtin_expect( (uint32_t) exp - 1U >= 2046, 0 ) ) 32 { // +-denorm, the other possibilities: +0 +-inf, NaN are screend out by caller 33 u.u |= 0x3ff0000000000000ULL; 34 u.d -= 1.0; 35 exp = (int32_t) (u.u >> 52); 36 37 return exp - (1023+1022); 38 } 39 40 return exp - 1023; 41} 42 43static inline double local_scalbn( double x, int n ); 44static inline double local_scalbn( double x, int n ) 45{ 46 union{ uint64_t u; double d;} u; 47 48 uint32_t absn = n >> (8*sizeof(n)-1); 49 absn = (n ^ absn) - absn; 50 51 if( absn > 1022 ) 52 { 53 // step = copysign( 1022, n ) 54 int signMask = n >> (8 * sizeof( int ) - 1); 55 int step = (1022 ^ signMask) - signMask; 56 57 u.u = ( (int64_t) step + 1023ULL) << 52; 58 59 if( n < 0 ) 60 { 61 do 62 { 63 x *= u.d; 64 n -= step; 65 }while( n < -1022 ); 66 } 67 else 68 { 69 do 70 { 71 x *= u.d; 72 n -= step; 73 }while( n > 1022 ); 74 } 75 } 76 77 //create 2**n in double 78 u.u = ( (int64_t) n + 1023ULL) << 52; 79 80 //scale by appropriate power of 2 81 x *= u.d; 82 83 //return result 84 return x; 85} 86 87 88double remainder( double x, double y ) 89{ 90 91 // deal with NaN 92 if( x != x || y != y ) 93 return x + y; 94 95 //x = Inf or y = 0, return Invalid per IEEE-754 96 double fabsx = __builtin_fabs(x); 97 if( fabsx == __builtin_inf() || 0.0 == y ) 98 { 99#ifdef ARMLIBM_SET_FLAGS 100 return required_add_double( __builtin_inf(), -__builtin_inf() ); //set invalid 101#else 102 return __builtin_nan(""); 103#endif 104 } 105 106 //handle trivial case 107 double fabsy = __builtin_fabs(y); 108 if( fabsy == __builtin_inf() || 0.0 == x ) 109 { 110#ifdef ARMLIBM_SET_FLAGS 111 required_add_double( fabsx, 0.0 ); // signal underflow (that is, no flag set, 112 // but exception occurs if unmasked) if x is denorm 113#endif 114 return x; 115 } 116 117 //we have to work 118 int32_t iquo = 0; 119 int32_t iscx = local_ilogb(fabsx); 120 int32_t iscy = local_ilogb(fabsy); 121 int32_t idiff = iscx - iscy; 122 double x1, y1, z; 123 x1 = fabsx; 124 y1 = fabsy; 125 if( idiff >= 0 ) 126 { 127 int32_t i; 128 129 if( idiff ) 130 { 131 y1 = local_scalbn( y1, -iscy ); 132 x1 = local_scalbn( x1, -iscx ); 133 for( i = idiff; i != 0; i-- ) 134 { 135 if( x1 >= y1 ) 136 { 137 x1 -= y1; 138 iquo += 1; 139 } 140 iquo += iquo; 141 x1 += x1; 142 } 143 x1 = local_scalbn( x1, iscy ); 144 } 145 if( x1 >= fabsy ) 146 { 147 x1 -= fabsy; 148 iquo += 1; 149 } 150 } 151 152 if( x1 < 0x1.0p1022 ) 153 { 154 z = x1 + x1; 155 if( (z > fabsy) || ((z == fabsy) & ((iquo & 1) != 0 ))) 156 x1 -= fabsy; 157 } 158 else 159 { 160 // x1 is only this large if y is even bigger, so we can safely divide y by 2 161 double halfy = 0.5*fabsy; 162 if( (x1 > halfy) || ((x1 == halfy) & ((iquo & 1) != 0 ))) 163 x1 -= fabsy; 164 } 165 166 167 if( x < 0 ) 168 x1 = -x1; 169 170 return x1; 171} 172