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 303fc5a433SBruce Evans static const double 313a8617a8SJordan K. Hubbard TWO52[2]={ 323a8617a8SJordan K. Hubbard 4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */ 333a8617a8SJordan K. Hubbard -4.50359962737049600000e+15, /* 0xC3300000, 0x00000000 */ 343a8617a8SJordan K. Hubbard }; 353a8617a8SJordan K. Hubbard 3659b19ff1SAlfred Perlstein double 373819e840SPeter Wemm rint(double x) 383a8617a8SJordan K. Hubbard { 393a8617a8SJordan K. Hubbard int32_t i0,j0,sx; 403a8617a8SJordan K. Hubbard u_int32_t i,i1; 413a8617a8SJordan K. Hubbard double w,t; 423a8617a8SJordan K. Hubbard EXTRACT_WORDS(i0,i1,x); 433a8617a8SJordan K. Hubbard sx = (i0>>31)&1; 443a8617a8SJordan K. Hubbard j0 = ((i0>>20)&0x7ff)-0x3ff; 453a8617a8SJordan K. Hubbard if(j0<20) { 463a8617a8SJordan K. Hubbard if(j0<0) { 473a8617a8SJordan K. Hubbard if(((i0&0x7fffffff)|i1)==0) return x; 483a8617a8SJordan K. Hubbard i1 |= (i0&0x0fffff); 493a8617a8SJordan K. Hubbard i0 &= 0xfffe0000; 503a8617a8SJordan K. Hubbard i0 |= ((i1|-i1)>>12)&0x80000; 513a8617a8SJordan K. Hubbard SET_HIGH_WORD(x,i0); 523a8617a8SJordan K. Hubbard w = TWO52[sx]+x; 533a8617a8SJordan K. Hubbard t = w-TWO52[sx]; 543a8617a8SJordan K. Hubbard GET_HIGH_WORD(i0,t); 553a8617a8SJordan K. Hubbard SET_HIGH_WORD(t,(i0&0x7fffffff)|(sx<<31)); 563a8617a8SJordan K. Hubbard return t; 573a8617a8SJordan K. Hubbard } else { 583a8617a8SJordan K. Hubbard i = (0x000fffff)>>j0; 593a8617a8SJordan K. Hubbard if(((i0&i)|i1)==0) return x; /* x is integral */ 603a8617a8SJordan K. Hubbard i>>=1; 613a8617a8SJordan K. Hubbard if(((i0&i)|i1)!=0) { 6274413775SBruce Evans /* 6374413775SBruce Evans * Some bit is set after the 0.5 bit. To avoid the 6474413775SBruce Evans * possibility of errors from double rounding in 6574413775SBruce Evans * w = TWO52[sx]+x, adjust the 0.25 bit to a lower 6674413775SBruce Evans * guard bit. We do this for all j0<=51. The 6774413775SBruce Evans * adjustment is trickiest for j0==18 and j0==19 6874413775SBruce Evans * since then it spans the word boundary. 6974413775SBruce Evans */ 703a8617a8SJordan K. Hubbard if(j0==19) i1 = 0x40000000; else 7174413775SBruce Evans if(j0==18) i1 = 0x80000000; else 723a8617a8SJordan K. Hubbard i0 = (i0&(~i))|((0x20000)>>j0); 733a8617a8SJordan K. Hubbard } 743a8617a8SJordan K. Hubbard } 753a8617a8SJordan K. Hubbard } else if (j0>51) { 763a8617a8SJordan K. Hubbard if(j0==0x400) return x+x; /* inf or NaN */ 773a8617a8SJordan K. Hubbard else return x; /* x is integral */ 783a8617a8SJordan K. Hubbard } else { 793a8617a8SJordan K. Hubbard i = ((u_int32_t)(0xffffffff))>>(j0-20); 803a8617a8SJordan K. Hubbard if((i1&i)==0) return x; /* x is integral */ 813a8617a8SJordan K. Hubbard i>>=1; 823a8617a8SJordan K. Hubbard if((i1&i)!=0) i1 = (i1&(~i))|((0x40000000)>>(j0-20)); 833a8617a8SJordan K. Hubbard } 843a8617a8SJordan K. Hubbard INSERT_WORDS(x,i0,i1); 853fc5a433SBruce Evans *(volatile double *)&w = TWO52[sx]+x; /* clip any extra precision */ 863a8617a8SJordan K. Hubbard return w-TWO52[sx]; 873a8617a8SJordan K. Hubbard } 88