Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /* Adapted for Newlib, 2009.  (Allow for int < 32 bits; return *quo=0 during
  2.  * errors to make test scripts easier.)  */
  3. /* @(#)e_fmod.c 1.3 95/01/18 */
  4. /*-
  5.  * ====================================================
  6.  * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
  7.  *
  8.  * Developed at SunSoft, a Sun Microsystems, Inc. business.
  9.  * Permission to use, copy, modify, and distribute this
  10.  * software is freely granted, provided that this notice
  11.  * is preserved.
  12.  * ====================================================
  13.  */
  14. /*
  15. FUNCTION
  16. <<remquo>>, <<remquof>>--remainder and part of quotient
  17. INDEX
  18.         remquo
  19. INDEX
  20.         remquof
  21.  
  22. ANSI_SYNOPSIS
  23.         #include <math.h>
  24.         double remquo(double <[x]>, double <[y]>, int *<[quo]>);
  25.         float remquof(float <[x]>, float <[y]>, int *<[quo]>);
  26.  
  27. DESCRIPTION
  28. The <<remquo>> functions compute the same remainder as the <<remainder>>
  29. functions; this value is in the range -<[y]>/2 ... +<[y]>/2.  In the object
  30. pointed to by <<quo>> they store a value whose sign is the sign of <<x>>/<<y>>
  31. and whose magnitude is congruent modulo 2**n to the magnitude of the integral
  32. quotient of <<x>>/<<y>>.  (That is, <<quo>> is given the n lsbs of the
  33. quotient, not counting the sign.)  This implementation uses n=31 if int is 32
  34. bits or more, otherwise, n is 1 less than the width of int.
  35.  
  36. For example:
  37. .       remquo(-29.0, 3.0, &<[quo]>)
  38. returns -1.0 and sets <[quo]>=10, and
  39. .       remquo(-98307.0, 3.0, &<[quo]>)
  40. returns -0.0 and sets <[quo]>=-32769, although for 16-bit int, <[quo]>=-1.  In
  41. the latter case, the actual quotient of -(32769=0x8001) is reduced to -1
  42. because of the 15-bit limitation for the quotient.
  43.  
  44. RETURNS
  45. When either argument is NaN, NaN is returned.  If <[y]> is 0 or <[x]> is
  46. infinite (and neither is NaN), a domain error occurs (i.e. the "invalid"
  47. floating point exception is raised or errno is set to EDOM), and NaN is
  48. returned.
  49. Otherwise, the <<remquo>> functions return <[x]> REM <[y]>.
  50.  
  51. BUGS
  52. IEEE754-2008 calls for <<remquo>>(subnormal, inf) to cause the "underflow"
  53. floating-point exception.  This implementation does not.
  54.  
  55. PORTABILITY
  56. C99, POSIX.
  57.  
  58. */
  59.  
  60. #include <limits.h>
  61. #include <math.h>
  62. #include "fdlibm.h"
  63.  
  64. /* For quotient, return either all 31 bits that can from calculation (using
  65.  * int32_t), or as many as can fit into an int that is smaller than 32 bits.  */
  66. #if INT_MAX > 0x7FFFFFFFL
  67.   #define QUO_MASK 0x7FFFFFFF
  68. # else
  69.   #define QUO_MASK INT_MAX
  70. #endif
  71.  
  72. static const double Zero[] = {0.0, -0.0,};
  73.  
  74. /*
  75.  * Return the IEEE remainder and set *quo to the last n bits of the
  76.  * quotient, rounded to the nearest integer.  We choose n=31--if that many fit--
  77.  * because we wind up computing all the integer bits of the quotient anyway as
  78.  * a side-effect of computing the remainder by the shift and subtract
  79.  * method.  In practice, this is far more bits than are needed to use
  80.  * remquo in reduction algorithms.
  81.  */
  82. double
  83. remquo(double x, double y, int *quo)
  84. {
  85.         __int32_t n,hx,hy,hz,ix,iy,sx,i;
  86.         __uint32_t lx,ly,lz,q,sxy;
  87.  
  88.         EXTRACT_WORDS(hx,lx,x);
  89.         EXTRACT_WORDS(hy,ly,y);
  90.         sxy = (hx ^ hy) & 0x80000000;
  91.         sx = hx&0x80000000;             /* sign of x */
  92.         hx ^=sx;                /* |x| */
  93.         hy &= 0x7fffffff;       /* |y| */
  94.  
  95.     /* purge off exception values */
  96.         if((hy|ly)==0||(hx>=0x7ff00000)||       /* y=0,or x not finite */
  97.           ((hy|((ly|-ly)>>31))>0x7ff00000))  {  /* or y is NaN */
  98.             *quo = 0;   /* Not necessary, but return consistent value */
  99.             return (x*y)/(x*y);
  100.         }
  101.         if(hx<=hy) {
  102.             if((hx<hy)||(lx<ly)) {
  103.                 q = 0;
  104.                 goto fixup;     /* |x|<|y| return x or x-y */
  105.             }
  106.             if(lx==ly) {
  107.                 *quo = (sxy ? -1 : 1);
  108.                 return Zero[(__uint32_t)sx>>31];        /* |x|=|y| return x*0 */
  109.             }
  110.         }
  111.  
  112.     /* determine ix = ilogb(x) */
  113.         if(hx<0x00100000) {     /* subnormal x */
  114.             if(hx==0) {
  115.                 for (ix = -1043, i=lx; i>0; i<<=1) ix -=1;
  116.             } else {
  117.                 for (ix = -1022,i=(hx<<11); i>0; i<<=1) ix -=1;
  118.             }
  119.         } else ix = (hx>>20)-1023;
  120.  
  121.     /* determine iy = ilogb(y) */
  122.         if(hy<0x00100000) {     /* subnormal y */
  123.             if(hy==0) {
  124.                 for (iy = -1043, i=ly; i>0; i<<=1) iy -=1;
  125.             } else {
  126.                 for (iy = -1022,i=(hy<<11); i>0; i<<=1) iy -=1;
  127.             }
  128.         } else iy = (hy>>20)-1023;
  129.  
  130.     /* set up {hx,lx}, {hy,ly} and align y to x */
  131.         if(ix >= -1022)
  132.             hx = 0x00100000|(0x000fffff&hx);
  133.         else {          /* subnormal x, shift x to normal */
  134.             n = -1022-ix;
  135.             if(n<=31) {
  136.                 hx = (hx<<n)|(lx>>(32-n));
  137.                 lx <<= n;
  138.             } else {
  139.                 hx = lx<<(n-32);
  140.                 lx = 0;
  141.             }
  142.         }
  143.         if(iy >= -1022)
  144.             hy = 0x00100000|(0x000fffff&hy);
  145.         else {          /* subnormal y, shift y to normal */
  146.             n = -1022-iy;
  147.             if(n<=31) {
  148.                 hy = (hy<<n)|(ly>>(32-n));
  149.                 ly <<= n;
  150.             } else {
  151.                 hy = ly<<(n-32);
  152.                 ly = 0;
  153.             }
  154.         }
  155.  
  156.     /* fix point fmod */
  157.         n = ix - iy;
  158.         q = 0;
  159.         while(n--) {
  160.             hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
  161.             if(hz<0){hx = hx+hx+(lx>>31); lx = lx+lx;}
  162.             else {hx = hz+hz+(lz>>31); lx = lz+lz; q++;}
  163.             q <<= 1;
  164.         }
  165.         hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
  166.         if(hz>=0) {hx=hz;lx=lz;q++;}
  167.  
  168.     /* convert back to floating value and restore the sign */
  169.         if((hx|lx)==0) {                        /* return sign(x)*0 */
  170.             q &= QUO_MASK;
  171.             *quo = (sxy ? -q : q);
  172.             return Zero[(__uint32_t)sx>>31];
  173.         }
  174.         while(hx<0x00100000) {          /* normalize x */
  175.             hx = hx+hx+(lx>>31); lx = lx+lx;
  176.             iy -= 1;
  177.         }
  178.         if(iy>= -1022) {        /* normalize output */
  179.             hx = ((hx-0x00100000)|((iy+1023)<<20));
  180.         } else {                /* subnormal output */
  181.             n = -1022 - iy;
  182.             if(n<=20) {
  183.                 lx = (lx>>n)|((__uint32_t)hx<<(32-n));
  184.                 hx >>= n;
  185.             } else if (n<=31) {
  186.                 lx = (hx<<(32-n))|(lx>>n); hx = sx;
  187.             } else {
  188.                 lx = hx>>(n-32); hx = sx;
  189.             }
  190.         }
  191. fixup:
  192.         INSERT_WORDS(x,hx,lx);
  193.         y = fabs(y);
  194.         if (y < 0x1p-1021) {
  195.             if (x+x>y || (x+x==y && (q & 1))) {
  196.                 q++;
  197.                 x-=y;
  198.             }
  199.         } else if (x>0.5*y || (x==0.5*y && (q & 1))) {
  200.             q++;
  201.             x-=y;
  202.         }
  203.         GET_HIGH_WORD(hx,x);
  204.         SET_HIGH_WORD(x,hx^sx);
  205.         q &= QUO_MASK;
  206.         *quo = (sxy ? -q : q);
  207.         return x;
  208. }
  209.