Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unexpected Behavior of Math.Floor(double) and Math.Ceiling(double)

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)?

like image 806
Ethan Brown Avatar asked Mar 28 '12 22:03

Ethan Brown


People also ask

What does Math Ceil Do What about Math Floor hint both floor and ceil expect floating point arguments?

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.

Why does Math ceiling return a double?

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.

Why is the Math floor 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.

What is ceiling method?

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.


2 Answers

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.

like image 64
Mark Byers Avatar answered Sep 20 '22 08:09

Mark Byers


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.

like image 34
Oliver Charlesworth Avatar answered Sep 20 '22 08:09

Oliver Charlesworth