13a8617a8SJordan K. Hubbard /* @(#)s_rint.c 5.1 93/09/24 */ 23a8617a8SJordan K. Hubbard /* 33a8617a8SJordan K. Hubbard * ==================================================== 43a8617a8SJordan K. Hubbard * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. 53a8617a8SJordan K. Hubbard * 63a8617a8SJordan K. Hubbard * Developed at SunPro, a Sun Microsystems, Inc. business. 73a8617a8SJordan K. Hubbard * Permission to use, copy, modify, and distribute this 83a8617a8SJordan K. Hubbard * software is freely granted, provided that this notice 93a8617a8SJordan K. Hubbard * is preserved. 103a8617a8SJordan K. Hubbard * ==================================================== 113a8617a8SJordan K. Hubbard */ 123a8617a8SJordan K. Hubbard 133a8617a8SJordan K. Hubbard #ifndef lint 147f3dea24SPeter Wemm static char rcsid[] = "$FreeBSD$"; 153a8617a8SJordan K. Hubbard #endif 163a8617a8SJordan K. Hubbard 173a8617a8SJordan K. Hubbard /* 183a8617a8SJordan K. Hubbard * rint(x) 193a8617a8SJordan K. Hubbard * Return x rounded to integral value according to the prevailing 203a8617a8SJordan K. Hubbard * rounding mode. 213a8617a8SJordan K. Hubbard * Method: 223a8617a8SJordan K. Hubbard * Using floating addition. 233a8617a8SJordan K. Hubbard * Exception: 243a8617a8SJordan K. Hubbard * Inexact flag raised if x not equal to rint(x). 253a8617a8SJordan K. Hubbard */ 263a8617a8SJordan K. Hubbard 273a8617a8SJordan K. Hubbard #include "math.h" 283a8617a8SJordan K. Hubbard #include "math_private.h" 293a8617a8SJordan K. Hubbard 302aa9f7caSBruce Evans /* 312aa9f7caSBruce Evans * TWO23 is long double instead of double to avoid a bug in gcc. Without 322aa9f7caSBruce Evans * this, gcc thinks that TWO23[sx]+x and w-TWO23[sx] already have double 332aa9f7caSBruce Evans * precision and doesn't clip them to double precision when they are 343ddc6e94SStefan Farfeleder * assigned and returned. 352aa9f7caSBruce Evans */ 362aa9f7caSBruce Evans static const long double 373a8617a8SJordan K. Hubbard TWO52[2]={ 383a8617a8SJordan K. Hubbard 4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */ 393a8617a8SJordan K. Hubbard -4.50359962737049600000e+15, /* 0xC3300000, 0x00000000 */ 403a8617a8SJordan K. Hubbard }; 413a8617a8SJordan K. Hubbard 4259b19ff1SAlfred Perlstein double 433819e840SPeter Wemm rint(double x) 443a8617a8SJordan K. Hubbard { 453a8617a8SJordan K. Hubbard int32_t i0,j0,sx; 463a8617a8SJordan K. Hubbard u_int32_t i,i1; 473a8617a8SJordan K. Hubbard double w,t; 483a8617a8SJordan K. Hubbard EXTRACT_WORDS(i0,i1,x); 493a8617a8SJordan K. Hubbard sx = (i0>>31)&1; 503a8617a8SJordan K. Hubbard j0 = ((i0>>20)&0x7ff)-0x3ff; 513a8617a8SJordan K. Hubbard if(j0<20) { 523a8617a8SJordan K. Hubbard if(j0<0) { 533a8617a8SJordan K. Hubbard if(((i0&0x7fffffff)|i1)==0) return x; 543a8617a8SJordan K. Hubbard i1 |= (i0&0x0fffff); 553a8617a8SJordan K. Hubbard i0 &= 0xfffe0000; 563a8617a8SJordan K. Hubbard i0 |= ((i1|-i1)>>12)&0x80000; 573a8617a8SJordan K. Hubbard SET_HIGH_WORD(x,i0); 583a8617a8SJordan K. Hubbard w = TWO52[sx]+x; 593a8617a8SJordan K. Hubbard t = w-TWO52[sx]; 603a8617a8SJordan K. Hubbard GET_HIGH_WORD(i0,t); 613a8617a8SJordan K. Hubbard SET_HIGH_WORD(t,(i0&0x7fffffff)|(sx<<31)); 623a8617a8SJordan K. Hubbard return t; 633a8617a8SJordan K. Hubbard } else { 643a8617a8SJordan K. Hubbard i = (0x000fffff)>>j0; 653a8617a8SJordan K. Hubbard if(((i0&i)|i1)==0) return x; /* x is integral */ 663a8617a8SJordan K. Hubbard i>>=1; 673a8617a8SJordan K. Hubbard if(((i0&i)|i1)!=0) { 6874413775SBruce Evans /* 6974413775SBruce Evans * Some bit is set after the 0.5 bit. To avoid the 7074413775SBruce Evans * possibility of errors from double rounding in 7174413775SBruce Evans * w = TWO52[sx]+x, adjust the 0.25 bit to a lower 7274413775SBruce Evans * guard bit. We do this for all j0<=51. The 7374413775SBruce Evans * adjustment is trickiest for j0==18 and j0==19 7474413775SBruce Evans * since then it spans the word boundary. 7574413775SBruce Evans */ 763a8617a8SJordan K. Hubbard if(j0==19) i1 = 0x40000000; else 7774413775SBruce Evans if(j0==18) i1 = 0x80000000; else 783a8617a8SJordan K. Hubbard i0 = (i0&(~i))|((0x20000)>>j0); 793a8617a8SJordan K. Hubbard } 803a8617a8SJordan K. Hubbard } 813a8617a8SJordan K. Hubbard } else if (j0>51) { 823a8617a8SJordan K. Hubbard if(j0==0x400) return x+x; /* inf or NaN */ 833a8617a8SJordan K. Hubbard else return x; /* x is integral */ 843a8617a8SJordan K. Hubbard } else { 853a8617a8SJordan K. Hubbard i = ((u_int32_t)(0xffffffff))>>(j0-20); 863a8617a8SJordan K. Hubbard if((i1&i)==0) return x; /* x is integral */ 873a8617a8SJordan K. Hubbard i>>=1; 883a8617a8SJordan K. Hubbard if((i1&i)!=0) i1 = (i1&(~i))|((0x40000000)>>(j0-20)); 893a8617a8SJordan K. Hubbard } 903a8617a8SJordan K. Hubbard INSERT_WORDS(x,i0,i1); 913a8617a8SJordan K. Hubbard w = TWO52[sx]+x; 923a8617a8SJordan K. Hubbard return w-TWO52[sx]; 933a8617a8SJordan K. Hubbard } 94