Ceiling
возвращает число, переданное ему, если они являются целыми числами, или же следующее высшее целое число. Так 5.0
остается 5.0
но 5.00001
становится 6.0
.
Таким образом, из примеров, следующие очевидны:
Math.Ceiling(123.121 * 100)/100 // Obtain 12312.1, next highest is 12313.0, then divide by 100 is 123.13
Math.Ceiling(123.1200000000001 * 100)/100 // Likewise
Math.Ceiling(123.12000000000002 * 100)/100 // Likewise
Чем больше сбивает с толку одно:
Math.Ceiling(123.12000000000001 * 100)/100 //display 123.12
Однако, давайте посмотрим на:
123.12000000000001 * 100 - 12312.0 // returns 0
По сравнению с:
123.1200000000001 * 100 - 12312.0 // returns 1.09139364212751E-11
123.12000000000002 * 100 - 12312.0 // returns 1.81898940354586E-12
Последние два умножений имеют результаты, которые немного выше, чем 12312.0, поэтому в то время как (123.12000000000002 * 100).ToString()
возвращается "12312"
действительное число, произведенное 123.12000000000002 * 100
математически 12312.000000000002
как можно ближе double
для 123.12000000000002
это является 123.1200000000000181898940354586
так это то, что работал.
Если вы привыкли только делать десятичную арифметику это может показаться странным, что 123.12000000000002
является «округлым» в 123.1200000000000181898940354586
, но помните, что эти числа хранятся в терминах двоичных значений, и округление зависит от базы вы работаете.
Так что, хотя строковое представление не указывает на это, оно действительно немного выше, чем 12312
, и поэтому его потолок 12313
.
Между тем с 123.12000000000001 * 100
, что математически 12312.000000000001
, но как можно ближе к double
123.12000000000001
является то, что он может вписаться в это 123.12
. Таким образом, это то, что используется для умножения, и когда результат передается на последующий вызов Ceiling()
, его результат равен 12312
.
некоторая форма прецизионных потерь – Andrey
Это связано с тем, что значения с плавающей запятой по своей сути являются неточными. См., Например, http://stackoverflow.com/questions/753948/why-is-floating-point-arithmetic-in-c-sharp-imprecise –
Это может быть связано с бинарными дробями (http: // с плавающей запятой .de/форматы/двоичные /). Поскольку float представлены двумя целыми числами в делении, не каждый float может использоваться. Это особенно характерно, когда у вас есть много нулей за разделителем с десятичной запятой, за которым следует 1 (как в ваших примерах). В этом случае поток округляется. Например, 123.12000000000001 может быть округлено до 123.12 до того, как оно будет передано потолочному методу. – Sascha