1570af302Sopenharmony_ci#include "libm.h" 2570af302Sopenharmony_ci 3570af302Sopenharmony_ci#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 4570af302Sopenharmony_cilong double fmodl(long double x, long double y) 5570af302Sopenharmony_ci{ 6570af302Sopenharmony_ci return fmod(x, y); 7570af302Sopenharmony_ci} 8570af302Sopenharmony_ci#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 9570af302Sopenharmony_cilong double fmodl(long double x, long double y) 10570af302Sopenharmony_ci{ 11570af302Sopenharmony_ci union ldshape ux = {x}, uy = {y}; 12570af302Sopenharmony_ci int ex = ux.i.se & 0x7fff; 13570af302Sopenharmony_ci int ey = uy.i.se & 0x7fff; 14570af302Sopenharmony_ci int sx = ux.i.se & 0x8000; 15570af302Sopenharmony_ci 16570af302Sopenharmony_ci if (y == 0 || isnan(y) || ex == 0x7fff) 17570af302Sopenharmony_ci return (x*y)/(x*y); 18570af302Sopenharmony_ci ux.i.se = ex; 19570af302Sopenharmony_ci uy.i.se = ey; 20570af302Sopenharmony_ci if (ux.f <= uy.f) { 21570af302Sopenharmony_ci if (ux.f == uy.f) 22570af302Sopenharmony_ci return 0*x; 23570af302Sopenharmony_ci return x; 24570af302Sopenharmony_ci } 25570af302Sopenharmony_ci 26570af302Sopenharmony_ci /* normalize x and y */ 27570af302Sopenharmony_ci if (!ex) { 28570af302Sopenharmony_ci ux.f *= 0x1p120f; 29570af302Sopenharmony_ci ex = ux.i.se - 120; 30570af302Sopenharmony_ci } 31570af302Sopenharmony_ci if (!ey) { 32570af302Sopenharmony_ci uy.f *= 0x1p120f; 33570af302Sopenharmony_ci ey = uy.i.se - 120; 34570af302Sopenharmony_ci } 35570af302Sopenharmony_ci 36570af302Sopenharmony_ci /* x mod y */ 37570af302Sopenharmony_ci#if LDBL_MANT_DIG == 64 38570af302Sopenharmony_ci uint64_t i, mx, my; 39570af302Sopenharmony_ci mx = ux.i.m; 40570af302Sopenharmony_ci my = uy.i.m; 41570af302Sopenharmony_ci for (; ex > ey; ex--) { 42570af302Sopenharmony_ci i = mx - my; 43570af302Sopenharmony_ci if (mx >= my) { 44570af302Sopenharmony_ci if (i == 0) 45570af302Sopenharmony_ci return 0*x; 46570af302Sopenharmony_ci mx = 2*i; 47570af302Sopenharmony_ci } else if (2*mx < mx) { 48570af302Sopenharmony_ci mx = 2*mx - my; 49570af302Sopenharmony_ci } else { 50570af302Sopenharmony_ci mx = 2*mx; 51570af302Sopenharmony_ci } 52570af302Sopenharmony_ci } 53570af302Sopenharmony_ci i = mx - my; 54570af302Sopenharmony_ci if (mx >= my) { 55570af302Sopenharmony_ci if (i == 0) 56570af302Sopenharmony_ci return 0*x; 57570af302Sopenharmony_ci mx = i; 58570af302Sopenharmony_ci } 59570af302Sopenharmony_ci for (; mx >> 63 == 0; mx *= 2, ex--); 60570af302Sopenharmony_ci ux.i.m = mx; 61570af302Sopenharmony_ci#elif LDBL_MANT_DIG == 113 62570af302Sopenharmony_ci uint64_t hi, lo, xhi, xlo, yhi, ylo; 63570af302Sopenharmony_ci xhi = (ux.i2.hi & -1ULL>>16) | 1ULL<<48; 64570af302Sopenharmony_ci yhi = (uy.i2.hi & -1ULL>>16) | 1ULL<<48; 65570af302Sopenharmony_ci xlo = ux.i2.lo; 66570af302Sopenharmony_ci ylo = uy.i2.lo; 67570af302Sopenharmony_ci for (; ex > ey; ex--) { 68570af302Sopenharmony_ci hi = xhi - yhi; 69570af302Sopenharmony_ci lo = xlo - ylo; 70570af302Sopenharmony_ci if (xlo < ylo) 71570af302Sopenharmony_ci hi -= 1; 72570af302Sopenharmony_ci if (hi >> 63 == 0) { 73570af302Sopenharmony_ci if ((hi|lo) == 0) 74570af302Sopenharmony_ci return 0*x; 75570af302Sopenharmony_ci xhi = 2*hi + (lo>>63); 76570af302Sopenharmony_ci xlo = 2*lo; 77570af302Sopenharmony_ci } else { 78570af302Sopenharmony_ci xhi = 2*xhi + (xlo>>63); 79570af302Sopenharmony_ci xlo = 2*xlo; 80570af302Sopenharmony_ci } 81570af302Sopenharmony_ci } 82570af302Sopenharmony_ci hi = xhi - yhi; 83570af302Sopenharmony_ci lo = xlo - ylo; 84570af302Sopenharmony_ci if (xlo < ylo) 85570af302Sopenharmony_ci hi -= 1; 86570af302Sopenharmony_ci if (hi >> 63 == 0) { 87570af302Sopenharmony_ci if ((hi|lo) == 0) 88570af302Sopenharmony_ci return 0*x; 89570af302Sopenharmony_ci xhi = hi; 90570af302Sopenharmony_ci xlo = lo; 91570af302Sopenharmony_ci } 92570af302Sopenharmony_ci for (; xhi >> 48 == 0; xhi = 2*xhi + (xlo>>63), xlo = 2*xlo, ex--); 93570af302Sopenharmony_ci ux.i2.hi = xhi; 94570af302Sopenharmony_ci ux.i2.lo = xlo; 95570af302Sopenharmony_ci#endif 96570af302Sopenharmony_ci 97570af302Sopenharmony_ci /* scale result */ 98570af302Sopenharmony_ci if (ex <= 0) { 99570af302Sopenharmony_ci ux.i.se = (ex+120)|sx; 100570af302Sopenharmony_ci ux.f *= 0x1p-120f; 101570af302Sopenharmony_ci } else 102570af302Sopenharmony_ci ux.i.se = ex|sx; 103570af302Sopenharmony_ci return ux.f; 104570af302Sopenharmony_ci} 105570af302Sopenharmony_ci#endif 106