Этот вопрос касается порога, при котором Math.Floor(double)
и Math.Ceiling(double)
решают дать вам предыдущее или следующее целочисленное значение.Я был встревожен, обнаружив, что порог, кажется, не имеет ничего общего с Double.Epsilon
, который является наименьшим значением, которое может быть представлено с двойным.Например:
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
Даже умножение Double.Epsilon
на справедливый бит не сработало:
Console.WriteLine( Math.Floor( x - Double.Epsilon*1000 ) ); // expected 2, got 3
Console.WriteLine( Math.Ceiling( x + Double.Epsilon*1000) ); // expected 4, got 3
С некоторыми экспериментами я смог определить, что пороггде-то около 2.2E-16, что очень мало, но НАМНОГО больше, чем Double.Epsilon
.
Причина, по которой возник этот вопрос, заключается в том, что я пытался вычислить количество цифр в числе по формуле var digits = Math.Floor( Math.Log( n, 10 ) ) + 1
.Эта формула не работает для n=1000
(на которую я наткнулся совершенно случайно), поскольку Math.Log( 1000, 10 )
возвращает число, равное 4.44E-16 от его действительного значения.(Позже я обнаружил, что встроенный Math.Log10(double)
обеспечивает гораздо более точные результаты.)
Не следует ли привязывать порог к Double.Epsilon
или, если нет, не документировать порог (Я не смог найти упоминаний об этом в официальной документации MSDN)?