Я получаю fmod, возвращая неправильный результат, я делаю что-то не так?
for($i = 0.00; $i < 1; $i = $i + 0.05) {
var_dump($i." = ".fmod($i, 0.05));
}
Выход:
0.= 0
0.05 = 0
0.1 = 0
0.15 = 1.3877787807814E-17
0.2 = 0
0.25 = 0.05
0.3 = 0.05
0.35 = 0.05
0.4 = 0.05
0.45 = 0.05
0.5 = 0.05
0.55 = 0.05
0.6 = 0.05
0.65 = 0.05
0.7 = 2.7755575615629E-17
0.75 = 6.9388939039072E-17
0.8 = 1.1102230246252E-16
0.85 = 1.5265566588596E-16
0.9 = 1.942890293094E-16
0.95 = 2.3592239273285E-16
Я ожидал, что каждый результат будет одинаковым: 0.
Первый, fmod
это точно. Потому что это может: когда x
а также y
являются числами с плавающей точкой, математический результат fmod(x,y)
может быть представлен точно как число с плавающей точкой.
Во-вторых, когда ты пишешь 0.05
, вы не получите точно это число, потому что 5/100 с другой стороны не может быть представлено точно как число с плавающей запятой; и когда ты пишешь +
вы не получите математическое сложение вообще, потому что результат этого математического сложения не всегда может быть представлен как число с плавающей запятой (*).
Начиная с 0,0 и многократного добавления 0,05, вы вскоре окажетесь неточными +
территория, потому что в двоичном представлении лучшее представление 0,05 имеет много цифр. По мере увеличения суммы последние цифры постепенно должны быть отброшены. Это где неточность +
исходит и, в конечном счете, является причиной, по которой fmod
не дает вам ожидаемых результатов.
Это не имеет значения, что 0.05
не точно 5/100, если многократно добавлять его к нулю всегда было точно. Но так как число с плавающей точкой 0.05
имеет много цифр в двоичном (в отличие от десятичного), и так как некоторые из этих цифр должны быть потеряны при вычислении кратных 0.05
, значение, которое вы получите для большинства магазинов y
из 0.05
при расчете fmod(y, 0.05)
не равно нулю, но представляет разницу между математическим умножением соответствующего целого числа на 0.05
и приближение y
из этого числа.
(*) когда математическая сумма может быть представлена, математическая сумма — это то, что вы получаете, но иногда это просто невозможно.
https://stackoverflow.com/revisions/28372286/1
Все работает нормально! Вы можете рассчитать это для себя:
fmod(0.5, 0.25);
fmod(0.5, 0.23);
fmod(0.5, 0.20);
0.25 * 2 = 0.50 | Rest 0.00
0.23 * 2 = 0.46 | Rest 0.04
0.20 * 2 = 0.40 | Rest 0.10