Тест нарушает основное правило программирования с плавающей запятой: никогда не проводить сравнения на равенство.
Существует ряд проблем, связанных с тем, что плавающееточечные дроби имеют большое, но конечное число битов.Эти проблемы обычно называют «ошибками округления» , хотя по большей части это не ошибки, а ограничения формата.
Например, из-за того, как мы пишем числа при программировании ... какдесятичные строки ... большинство чисел, которые мы можем записать, не имеют соответствующего представления в формате с плавающей запятой, если они имеют десятичную дробь.Дробная часть повторяется в базе два.
Это в значительной степени исключает точное сравнение чисел с плавающей запятой, за исключением, по иронии судьбы, между целыми значениями. Вам необходимо реализовать нечеткое сравнение, такое как abs(a - b) < epsilon.
И на самом деле ваш 2/9
- это случай с джекпотом, который не имеет конечного представления как десятичная строка или двоичная строка! 1
Для успешного сравнения 2/9
на равенство сконстанта предъявляет к программе, интерпретатору и библиотеке больше требований к совершенству, чем можно рассчитывать.
Например, вам придется набирать 2
s больше, чем нужно, а интерпретатору придется округлятьмладшие биты константы со знанием большей точности, чем формат.На самом деле машина имеет несколько дополнительных знаний при выполнении операции, но интерпретатор может этого не делать при преобразовании константы.Кроме того, округление во время выполнения зависит от различных опций, и язык, такой как PHP, может даже не определять точно, как непредставимые константы округляются от исходного кода до внутренней формы.
И на самом деле это хуже , чем этопотому что отдельные компоненты 0,2 / 10 n в десятичной строке также не имеют точных двоичных эквивалентов.Таким образом, вполне вероятно, что действительно совершенное и точное преобразование 0.22222222222222
действительно не фактически соответствует представлению с максимальным усилием действительного 2/9
.Вы не можете выразить в виде конечной десятичной строки точную дробь base-2, которая наиболее точно представляет 2/9 в любом конкретном (конечном) количестве бит.
(У нас должен быть где-то стандартный ответ о том, что не нужно сравнивать равенствос числами с плавающей запятой.)
1.Каждая дробь машины - это рациональное число вида х / 2 n .Теперь константы являются десятичными, и каждая десятичная константа является рациональным числом вида x / (2 n * 5 m ).Числа 5 m являются нечетными, поэтому для любого из них нет коэффициента 2 n .Только когда m == 0, есть конечное представление как в двоичном, так и в десятичном разложении дроби.Например, 1.25
является точным, потому что это 5 / (2 2 * 5 0 ), но 0.1
не потому, что это 1 / (2 0 * 5 * 1 * тысяча семьдесят-три ).А для рационального числа 2/9
не существует ни 2 n , ни a 5 m factor.