diff --git a/sonoff/support_float.ino b/sonoff/support_float.ino index 3809fd6ec..6e9379a53 100644 --- a/sonoff/support_float.ino +++ b/sonoff/support_float.ino @@ -17,93 +17,73 @@ along with this program. If not, see . */ -#ifdef ARDUINO_ESP8266_RELEASE_2_3_0 +//#ifdef ARDUINO_ESP8266_RELEASE_2_3_0 // Functions not available in 2.3.0 -// https://code.woboq.org/userspace/glibc/sysdeps/ieee754/flt-32/e_fmodf.c.html float fmodf(float x, float y) { - const float Zero[] = { 0.0, -0.0 }; + // https://github.com/micropython/micropython/blob/master/lib/libm/fmodf.c + union {float f; uint32_t i;} ux = {x}, uy = {y}; + int ex = ux.i>>23 & 0xff; + int ey = uy.i>>23 & 0xff; + uint32_t sx = ux.i & 0x80000000; + uint32_t i; + uint32_t uxi = ux.i; - int32_t hx = (int32_t)x; - int32_t hy = (int32_t)y; - - int32_t sx = hx &0x80000000; // sign of x - hx ^= sx; // |x| - hy &= 0x7fffffff; // |y| - - // purge off exception values - if ((0 == hy) || (hx >= 0x7f800000) || (hy > 0x7f800000)) { // y=0, or x not finite, or y is NaN - return (x * y) / (x * y); + if (uy.i<<1 == 0 || isnan(y) || ex == 0xff) + return (x*y)/(x*y); + if (uxi<<1 <= uy.i<<1) { + if (uxi<<1 == uy.i<<1) + return 0*x; + return x; } - if (hx < hy) { return x; } // |x|<|y| return x - if (hx == hy) { return Zero[(uint32_t)sx >> 31]; } // |x|=|y| return x*0 - int32_t n, hz, ix, iy, i; - // determine ix = ilogb(x) - if (hx < 0x00800000) { // subnormal x - for (ix = -126, i = (hx << 8); i > 0; i <<= 1) { ix -=1; } + // normalize x and y + if (!ex) { + for (i = uxi<<9; i>>31 == 0; ex--, i <<= 1); + uxi <<= -ex + 1; } else { - ix = (hx >> 23) -127; + uxi &= -1U >> 9; + uxi |= 1U << 23; } - - // determine iy = ilogb(y) - if (hy < 0x00800000) { // subnormal y - for (iy = -126, i = (hy << 8); i >= 0; i <<= 1) { iy -=1; } + if (!ey) { + for (i = uy.i<<9; i>>31 == 0; ey--, i <<= 1); + uy.i <<= -ey + 1; } else { - iy = (hy >> 23) -127; + uy.i &= -1U >> 9; + uy.i |= 1U << 23; } - // set up {hx,lx}, {hy,ly} and align y to x - if (ix >= -126) { - hx = 0x00800000 | (0x007fffff & hx); - } else { // subnormal x, shift x to normal - n = -126 - ix; - hx = hx << n; - } - if (iy >= -126) { - hy = 0x00800000 | (0x007fffff & hy); - } else { // subnormal y, shift y to normal - n = -126 - iy; - hy = hy << n; - } - - // fix point fmod - n = ix - iy; - while (n--) { - hz = hx - hy; - if (hz < 0) { - hx = hx + hx; - } else { - if (hz == 0) { // return sign(x)*0 - return Zero[(uint32_t)sx >> 31]; - } - hx = hz + hz; + // x mod y + for (; ex > ey; ex--) { + i = uxi - uy.i; + if (i >> 31 == 0) { + if (i == 0) + return 0*x; + uxi = i; } + uxi <<= 1; } - hz = hx - hy; - if (hz >= 0) { hx = hz; } + i = uxi - uy.i; + if (i >> 31 == 0) { + if (i == 0) + return 0*x; + uxi = i; + } + for (; uxi>>23 == 0; uxi <<= 1, ex--); - // convert back to floating value and restore the sign - if (0 == hx) { // return sign(x)*0 - return Zero[(uint32_t)sx >> 31]; + // scale result up + if (ex > 0) { + uxi -= 1U << 23; + uxi |= (uint32_t)ex << 23; + } else { + uxi >>= -ex + 1; } - while (hx < 0x00800000) { // normalize x - hx = hx + hx; - iy -= 1; - } - if (iy >= -126) { // normalize output - hx = ((hx - 0x00800000) | ((iy +127) << 23)); - x = (float)(hx | sx); - } else { // subnormal output - n = -126 - iy; - hx >>= n; - x = (float)(hx | sx); - x *= 1.0; // create necessary signal - } - return x; // exact output + uxi |= sx; + ux.i = uxi; + return ux.f; } -#endif // ARDUINO_ESP8266_RELEASE_2_3_0 +//#endif // ARDUINO_ESP8266_RELEASE_2_3_0 double FastPrecisePow(double a, double b) {