/* * fmod.c * cLibm * * Written by Jon Okada, started on December 7th, 1992. * Modified by Paul Finlayson (PAF) for MathLib v2. * Modified by A. Sazegari (ali) for MathLib v3. * Modified and ported by Robert A. Murley (ram) for Mac OS X. * Modified for cLibm, fixed a few edge cases, rewrote local_ funcs by Ian Ollmann. * Modified for armLibm, removed code to set flags as this is a soft-float fallback only. * * Copyright 2007 Apple Inc. All rights reserved. * */ /* * Modified for ALMOS-MKH OS at UPMC, France, August 2018. (Alain Greiner) */ #include "math.h" #include "math_private.h" double fmod(double x, double y) { union { double d; uint64_t u; } ux = {x}; union { double d; uint64_t u; } uy = {y}; uint64_t absx = ux.u & ~0x8000000000000000ULL; uint64_t absy = uy.u & ~0x8000000000000000ULL; if (absx - 1ULL >= 0x7fefffffffffffffULL || absy - 1ULL >= 0x7fefffffffffffffULL) { double fabsx = fabs(x); double fabsy = fabs(y); // deal with NaN if (x != x || y != y) { return x + y; } // x = Inf or y = 0, return Invalid per IEEE-754 if (!isfinite(fabsx) || 0.0 == y) { return 0.0 / 0.0; // NaN } // handle trivial case if (!isfinite(fabsy) || 0.0 == x) { return x; } } if (absy >= absx) { if (absy == absx) { ux.u ^= absx; return ux.d; } return x; } int32_t expx = absx >> 52; int32_t expy = absy >> 52; int64_t sx = absx & 0x000fffffffffffffULL; int64_t sy = absy & 0x000fffffffffffffULL; if (0 == expx) { uint32_t shift = __builtin_clzll(absx) - (64 - 53); sx <<= shift; expx = 1 - shift; } if (0 == expy) { uint32_t shift = __builtin_clzll(absy) - (64 - 53); sy <<= shift; expy = 1 - shift; } sx |= 0x0010000000000000ULL; sy |= 0x0010000000000000ULL; int32_t idiff = expx - expy; int32_t shift = 0; int64_t mask; do { sx <<= shift; idiff += ~shift; sx -= sy; mask = sx >> 63; sx += sx; sx += sy & mask; shift = __builtin_clzll(sx) - (64 - 53); } while (idiff >= shift && sx != 0LL); if (idiff < 0) { sx += sy & mask; sx >>= 1; idiff = 0; } sx <<= idiff; if (0 == sx) { ux.u &= 0x8000000000000000ULL; return ux.d; } shift = __builtin_clzll(sx) - (64 - 53); sx <<= shift; expy -= shift; sx &= 0x000fffffffffffffULL; sx |= ux.u & 0x8000000000000000ULL; if (expy > 0) { ux.u = sx | ((int64_t) expy << 52); return ux.d; } expy += 1022; ux.u = sx | ((int64_t) expy << 52); return ux.d * 0x1.0p-1022; }