Почему sprintf не уверен в 5 раунде?

Я полагался на sprintf('%0.1f', 2.25) === '2.3' но, оказывается, он приходит в 2.2 !

На самом деле это кажется случайным:

 php > for ($j=0;$j<=10;$j++) { printf( "%s -> %0.1f\n",$j+ 0.05, $j+0.05); } 0.05 -> 0.1 // Up, as expected 1.05 -> 1.1 // Up, as expected 2.05 -> 2.0 // Down! 3.05 -> 3.0 // Down! 4.05 -> 4.0 // Down! 5.05 -> 5.0 // Down! 6.05 -> 6.0 // Down! 7.05 -> 7.0 // Down! 8.05 -> 8.1 // Up, as expected 9.05 -> 9.1 // Up, as expected 

Я полностью упустил момент? Я чувствую, что из-под меня убирают коврик и что все, что я узнал в школе, ошибается …! Разумеется, функция округления чисел должна делать это последовательно? (Я отмечаю, что round($n, 1) работает так, как ожидалось.)

Related of "Почему sprintf не уверен в 5 раунде?"

В качестве объяснения того, почему round может предложить лучшие результаты, чем функция, специально не предназначенная для округления, нам нужно рассмотреть пределы представления с плавающей запятой двойной точности. Партии могут представлять от 15 до 17 значащих значащих цифр. Из статьи Википедии о двойной точности :

Если десятичная строка длиной не более 15 значащих цифр преобразуется в представление двойной точности IEEE 754, а затем преобразуется обратно в строку с таким же количеством значащих цифр, то окончательная строка должна соответствовать оригиналу. Если двойная точность IEEE 754 преобразуется в десятичную строку с не менее 17 значащими цифрами, а затем преобразуется обратно в двойную, то окончательное число должно совпадать с оригиналом

Реализация round может и должна использовать это, чтобы «делать правильные вещи» в большинстве случаев.

Пример 1:

 <?=number_format(2.05,14); //give me 15 significant digits. Guaranteed to produce the orginal number 

выходы:

 2.05000000000000 

Пример 2:

 <?=number_format(2.05,16); //give me 17 significant digits. Not guaranteed to produce the orginal number 

выходы:

 2.0499999999999998 

Это всего лишь демонстрация поведения IEEE 754.

Я собираюсь угадать (потому что я не читал его реализации), что sprintf самом деле не пытается сделать что-то особенно интеллектуальное в отношении округления, тогда как round вероятно, пытается округлить «правильно» (по IEEE 754) относительно количество важных цифр, которые вы просили.

Вы должны использовать round

http://php.net/manual/en/function.round.php

 round(2.25, 2) === floatval('2.3') 

Подводя итог тому, что было сказано в комментариях в ответе:

Потому что printf не является функцией округления , а функцией низкого уровня, чтобы дать строковое представление числа. В этом случае число внутри не совпадает с номером, например, оно может быть 2.249999991231231123 из-за ограничений внутреннего представления с плавающей запятой.

Таким образом, printf округляет другое число до того, что вы ввели / вычислено, что в этом примере правильно 2.2 .

Поэтому, как указывает другой ответ (и мой первоначальный вопрос), лучшим решением является использование round() (и, возможно, sprintf для результата).