1a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes/* @(#)e_fmod.c 1.3 95/01/18 */ 2a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes/*- 3a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes * ==================================================== 4a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. 5a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes * 6a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes * Developed at SunSoft, a Sun Microsystems, Inc. business. 7a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes * Permission to use, copy, modify, and distribute this 8a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes * software is freely granted, provided that this notice 9a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes * is preserved. 10a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes * ==================================================== 11a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes */ 12a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes 13a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes#include <sys/cdefs.h> 14a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes__FBSDID("$FreeBSD$"); 15a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes 16a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes#include <float.h> 17a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes#include <stdint.h> 18a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes 19a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes#include "fpmath.h" 20a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes#include "math.h" 21a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes#include "math_private.h" 22a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes 23a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes#define BIAS (LDBL_MAX_EXP - 1) 24a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes 25a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes#if LDBL_MANL_SIZE > 32 26a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughestypedef uint64_t manl_t; 27a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes#else 28a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughestypedef uint32_t manl_t; 29a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes#endif 30a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes 31a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes#if LDBL_MANH_SIZE > 32 32a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughestypedef uint64_t manh_t; 33a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes#else 34a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughestypedef uint32_t manh_t; 35a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes#endif 36a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes 37a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes/* 38a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes * These macros add and remove an explicit integer bit in front of the 39a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes * fractional mantissa, if the architecture doesn't have such a bit by 40a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes * default already. 41a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes */ 42a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes#ifdef LDBL_IMPLICIT_NBIT 43a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes#define SET_NBIT(hx) ((hx) | (1ULL << LDBL_MANH_SIZE)) 44a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes#define HFRAC_BITS LDBL_MANH_SIZE 45a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes#else 46a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes#define SET_NBIT(hx) (hx) 47a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes#define HFRAC_BITS (LDBL_MANH_SIZE - 1) 48a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes#endif 49a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes 50a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes#define MANL_SHIFT (LDBL_MANL_SIZE - 1) 51a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes 52a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughesstatic const long double one = 1.0, Zero[] = {0.0, -0.0,}; 53a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes 54a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes/* 55a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes * fmodl(x,y) 56a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes * Return x mod y in exact arithmetic 57a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes * Method: shift and subtract 58a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes * 59a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes * Assumptions: 60a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes * - The low part of the mantissa fits in a manl_t exactly. 61a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes * - The high part of the mantissa fits in an int64_t with enough room 62a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes * for an explicit integer bit in front of the fractional bits. 63a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes */ 64a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hugheslong double 65a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughesfmodl(long double x, long double y) 66a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes{ 67a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes union IEEEl2bits ux, uy; 68a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes int64_t hx,hz; /* We need a carry bit even if LDBL_MANH_SIZE is 32. */ 69a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes manh_t hy; 70a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes manl_t lx,ly,lz; 71a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes int ix,iy,n,sx; 72a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes 73a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes ux.e = x; 74a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes uy.e = y; 75a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes sx = ux.bits.sign; 76a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes 77a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes /* purge off exception values */ 78a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes if((uy.bits.exp|uy.bits.manh|uy.bits.manl)==0 || /* y=0 */ 79a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes (ux.bits.exp == BIAS + LDBL_MAX_EXP) || /* or x not finite */ 80a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes (uy.bits.exp == BIAS + LDBL_MAX_EXP && 81a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes ((uy.bits.manh&~LDBL_NBIT)|uy.bits.manl)!=0)) /* or y is NaN */ 82a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes return (x*y)/(x*y); 83a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes if(ux.bits.exp<=uy.bits.exp) { 84a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes if((ux.bits.exp<uy.bits.exp) || 85a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes (ux.bits.manh<=uy.bits.manh && 86a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes (ux.bits.manh<uy.bits.manh || 87a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes ux.bits.manl<uy.bits.manl))) { 88a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes return x; /* |x|<|y| return x or x-y */ 89a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes } 90a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes if(ux.bits.manh==uy.bits.manh && ux.bits.manl==uy.bits.manl) { 91a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes return Zero[sx]; /* |x|=|y| return x*0*/ 92a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes } 93a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes } 94a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes 95a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes /* determine ix = ilogb(x) */ 96a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes if(ux.bits.exp == 0) { /* subnormal x */ 97a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes ux.e *= 0x1.0p512; 98a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes ix = ux.bits.exp - (BIAS + 512); 99a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes } else { 100a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes ix = ux.bits.exp - BIAS; 101a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes } 102a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes 103a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes /* determine iy = ilogb(y) */ 104a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes if(uy.bits.exp == 0) { /* subnormal y */ 105a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes uy.e *= 0x1.0p512; 106a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes iy = uy.bits.exp - (BIAS + 512); 107a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes } else { 108a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes iy = uy.bits.exp - BIAS; 109a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes } 110a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes 111a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes /* set up {hx,lx}, {hy,ly} and align y to x */ 112a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes hx = SET_NBIT(ux.bits.manh); 113a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes hy = SET_NBIT(uy.bits.manh); 114a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes lx = ux.bits.manl; 115a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes ly = uy.bits.manl; 116a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes 117a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes /* fix point fmod */ 118a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes n = ix - iy; 119a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes 120a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes while(n--) { 121a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1; 122a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes if(hz<0){hx = hx+hx+(lx>>MANL_SHIFT); lx = lx+lx;} 123a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes else { 124a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes if ((hz|lz)==0) /* return sign(x)*0 */ 125a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes return Zero[sx]; 126a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes hx = hz+hz+(lz>>MANL_SHIFT); lx = lz+lz; 127a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes } 128a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes } 129a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1; 130a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes if(hz>=0) {hx=hz;lx=lz;} 131a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes 132a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes /* convert back to floating value and restore the sign */ 133a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes if((hx|lx)==0) /* return sign(x)*0 */ 134a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes return Zero[sx]; 135a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes while(hx<(1ULL<<HFRAC_BITS)) { /* normalize x */ 136a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes hx = hx+hx+(lx>>MANL_SHIFT); lx = lx+lx; 137a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes iy -= 1; 138a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes } 139a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes ux.bits.manh = hx; /* The mantissa is truncated here if needed. */ 140a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes ux.bits.manl = lx; 141a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes if (iy < LDBL_MIN_EXP) { 142a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes ux.bits.exp = iy + (BIAS + 512); 143a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes ux.e *= 0x1p-512; 144a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes } else { 145a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes ux.bits.exp = iy + BIAS; 146a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes } 147a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes x = ux.e * one; /* create necessary signal */ 148a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes return x; /* exact output */ 149a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes} 150