This question is about the threshold at which Math.Floor(double)
and Math.Ceiling(double)
decide to give you the previous or next integer value. I was disturbed to find that the threshold seems to have nothing to do with Double.Epsilon
, which is the smallest value that can be represented with a double. For example:
double x = 3.0;
Console.WriteLine( Math.Floor( x - Double.Epsilon ) ); // expected 2, got 3
Console.WriteLine( Math.Ceiling( x + Double.Epsilon) ); // expected 4, got 3
Even multiplying Double.Epsilon
by a fair bit didn't do the trick:
Console.WriteLine( Math.Floor( x - Double.Epsilon*1000 ) ); // expected 2, got 3
Console.WriteLine( Math.Ceiling( x + Double.Epsilon*1000) ); // expected 4, got 3
With some experimentation, I was able to determine that the threshold is somewhere around 2.2E-16, which is very small, but VASTLY bigger than Double.Epsilon
.
The reason this question came up is that I was trying to calculate the number of digits in a number with the formula var digits = Math.Floor( Math.Log( n, 10 ) ) + 1
. This formula doesn't work for n=1000
(which I stumbled on completely by accident) because Math.Log( 1000, 10 )
returns a number that's 4.44E-16 off its actual value. (I later found that the built-in Math.Log10(double)
provides much more accurate results.)
Shouldn't the threshold should be tied to Double.Epsilon
or, if not, shouldn't the threshold be documented (I couldn't find any mention of this in the official MSDN documentation)?
ceil(x) Return the ceiling of x as a float, the smallest integer value greater than or equal to x. math. floor(x) Return the floor of x as a float, the largest integer value less than or equal to x.
The documentation says about the return value: The smallest whole number greater than or equal to a. If a is equal to NaN, NegativeInfinity, or PositiveInfinity, that value is returned. Therefore the return value has to be double since NaN, NegativeInfinity and PositiveInfinity are fields of Double.
Floor leaves it as a double so you can do more double calculations with it. If you want it as an int, cast the result of floor as an int.
Ceiling() is a Math class method. This method is used to find the smallest integer , which is greater than or equal to the passed argument. The Ceiling method operates both functionalities in decimal and double. This method can be overload by passing different arguments to it. Math.Ceiling(Decimal) Method.
Shouldn't the threshold should be tied to Double.Epsilon
No.
The representable doubles are not uniformly distributed over the real numbers. Close to zero there are many representable values. But the further from zero you get, the further apart representable doubles are. For very large numbers even adding 1 to a double will not give you a new value.
Therefore the threshold you are looking for depends on how large your number is. It is not a constant.
The value of Double.Epsilon
is 4.94065645841247e-324. Adding or subtracting this value to 3 results in 3, due to the way floating-point works.
A double
has 53 bits of mantissa, so the smallest value you can add that will have any impact will be approximately 2^53 time smaller than your variable. So something around 1e-16 sounds about right (order of magnitude).
So to answer your question: there is no "threshold"; floor
and ceil
simply act on their argument in exactly the way you would expect.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With