1
0
mirror of https://github.com/postgres/postgres.git synced 2025-08-18 12:22:09 +03:00
Files
postgres/src/port/rint.c
Alvaro Herrera f2c587067a Rethink how to get float.h in old Windows API for isnan/isinf
We include <float.h> in every place that needs isnan(), because MSVC
used to require it.  However, since MSVC 2013 that's no longer necessary
(cf. commit cec8394b5c), so we can retire the inclusion to a
version-specific stanza in win32_port.h, where it doesn't need to
pollute random .c files.  The header is of course still needed in a few
places for other reasons.

I (Álvaro) removed float.h from a few more files than in Emre's original
patch.  This doesn't break the build in my system, but we'll see what
the buildfarm has to say about it all.

Author: Emre Hasegeli
Discussion: https://postgr.es/m/CAE2gYzyc0+5uG+Cd9-BSL7NKC8LSHLNg1Aq2=8ubjnUwut4_iw@mail.gmail.com
2018-07-11 09:11:48 -04:00

98 lines
2.3 KiB
C

/*-------------------------------------------------------------------------
*
* rint.c
* rint() implementation
*
* By Pedro Gimeno Fortea, donated to the public domain
*
* IDENTIFICATION
* src/port/rint.c
*
*-------------------------------------------------------------------------
*/
#include "c.h"
#include <math.h>
/*
* Round to nearest integer, with halfway cases going to the nearest even.
*/
double
rint(double x)
{
double x_orig;
double r;
/* Per POSIX, NaNs must be returned unchanged. */
if (isnan(x))
return x;
if (x <= 0.0)
{
/* Both positive and negative zero should be returned unchanged. */
if (x == 0.0)
return x;
/*
* Subtracting 0.5 from a number very close to -0.5 can round to
* exactly -1.0, producing incorrect results, so we take the opposite
* approach: add 0.5 to the negative number, so that it goes closer to
* zero (or at most to +0.5, which is dealt with next), avoiding the
* precision issue.
*/
x_orig = x;
x += 0.5;
/*
* Be careful to return minus zero when input+0.5 >= 0, as that's what
* rint() should return with negative input.
*/
if (x >= 0.0)
return -0.0;
/*
* For very big numbers the input may have no decimals. That case is
* detected by testing x+0.5 == x+1.0; if that happens, the input is
* returned unchanged. This also covers the case of minus infinity.
*/
if (x == x_orig + 1.0)
return x_orig;
/* Otherwise produce a rounded estimate. */
r = floor(x);
/*
* If the rounding did not produce exactly input+0.5 then we're done.
*/
if (r != x)
return r;
/*
* The original fractional part was exactly 0.5 (since
* floor(input+0.5) == input+0.5). We need to round to nearest even.
* Dividing input+0.5 by 2, taking the floor and multiplying by 2
* yields the closest even number. This part assumes that division by
* 2 is exact, which should be OK because underflow is impossible
* here: x is an integer.
*/
return floor(x * 0.5) * 2.0;
}
else
{
/*
* The positive case is similar but with signs inverted and using
* ceil() instead of floor().
*/
x_orig = x;
x -= 0.5;
if (x <= 0.0)
return 0.0;
if (x == x_orig - 1.0)
return x_orig;
r = ceil(x);
if (r != x)
return r;
return ceil(x * 0.5) * 2.0;
}
}