1 /*------------------------------------------------------------------------- 2 * 3 * rint.c 4 * rint() implementation 5 * 6 * By Pedro Gimeno Fortea, donated to the public domain main(void)7 * 8 * IDENTIFICATION 9 * src/port/rint.c 10 * 11 *------------------------------------------------------------------------- 12 */ 13 #include "c.h" 14 15 #include <float.h> 16 #include <math.h> 17 18 /* 19 * Round to nearest integer, with halfway cases going to the nearest even. 20 */ 21 double 22 rint(double x) 23 { 24 double x_orig; 25 double r; 26 27 /* Per POSIX, NaNs must be returned unchanged. */ 28 if (isnan(x)) 29 return x; 30 31 if (x <= 0.0) 32 { 33 /* Both positive and negative zero should be returned unchanged. */ 34 if (x == 0.0) 35 return x; 36 37 /* 38 * Subtracting 0.5 from a number very close to -0.5 can round to 39 * exactly -1.0, producing incorrect results, so we take the opposite 40 * approach: add 0.5 to the negative number, so that it goes closer to 41 * zero (or at most to +0.5, which is dealt with next), avoiding the 42 * precision issue. 43 */ 44 x_orig = x; 45 x += 0.5; 46 47 /* 48 * Be careful to return minus zero when input+0.5 >= 0, as that's what 49 * rint() should return with negative input. 50 */ 51 if (x >= 0.0) 52 return -0.0; 53 54 /* 55 * For very big numbers the input may have no decimals. That case is 56 * detected by testing x+0.5 == x+1.0; if that happens, the input is 57 * returned unchanged. This also covers the case of minus infinity. 58 */ 59 if (x == x_orig + 1.0) 60 return x_orig; 61 62 /* Otherwise produce a rounded estimate. */ 63 r = floor(x); 64 65 /* 66 * If the rounding did not produce exactly input+0.5 then we're done. 67 */ 68 if (r != x) 69 return r; 70 71 /* 72 * The original fractional part was exactly 0.5 (since 73 * floor(input+0.5) == input+0.5). We need to round to nearest even. 74 * Dividing input+0.5 by 2, taking the floor and multiplying by 2 75 * yields the closest even number. This part assumes that division by 76 * 2 is exact, which should be OK because underflow is impossible 77 * here: x is an integer. 78 */ 79 return floor(x * 0.5) * 2.0; 80 } 81 else 82 { 83 /* 84 * The positive case is similar but with signs inverted and using 85 * ceil() instead of floor(). 86 */ 87 x_orig = x; 88 x -= 0.5; 89 if (x <= 0.0) 90 return 0.0; 91 if (x == x_orig - 1.0) 92 return x_orig; 93 r = ceil(x); 94 if (r != x) 95 return r; 96 return ceil(x * 0.5) * 2.0; 97 } 98 } 99