Преамбула
Некоторое время материалы этого урока были "почти" готовы и теперь с некоторыми доработками я представлю их на изучение аудиторией.
Речь пойдет о некоторых особенностях вещественного типа в PHP.
О чем, собственно, идет речь
Сам предмет изучения - тип float в PHP. Он же - double. На деле float - это тип с так называемой "одинарной" точностью, а double - с "двойной" точностью. И это два разных типа данных. Однако в PHP это не так. Диапазон значений переменных в этом типе по-умолчанию следует стандарту 64-битного IEEE-формата, то есть ~1.8x10308 с точностью около 14 десятичных цифр. Однако следует учитывать, что это зависит от платформы.
В данном приложении будут рассмотрены две вещи о числах с плавающей точкой. Идем далее.
О том, что дискретное - не дискретно
По-хорошему (а точнее, алгебраически), тип данных с плавающей точкой есть "подделка" числовой прямой. То есть должен иметь непрерывные значения. Реализовать такое при современном уровне технологий не представляется возможным, так как и сама архитектура вычислительных машин - дискретна. Соответственно, вещественный тип данных, разумеется, не имеет мощности "континуум" (для любителей теории множеств - он, разумеется, не имеет и мощности "алеф ноль").
Из этого следует первая важная особенность: значения всех алгебраических функций будут представляться приближенно. Все иррациональные числа в представлении float - рациональны (ввиду ограничений точности). То есть иррациональные числа представлены приближенно.
Что же с рациональными? Увы, здесь тоже не все очевидно. Дело в том, что вещественный тип данных, как и целочисленный, представляется в двоичном виде. Это и понятно, ведь все операции происходят на архитектуре, построенном на двоичном представлении. Здесь мы подходим к одному важному вопросу - а как, собственно, этот тип данных устроен?
Об устройстве
С технической точки зрения, число с плавающей точкой состоит из знака, порядка и мантиссы.
Если подходить алгебраически, то связаны они так:
Здесь s - знак, m - мантисса, b - основание, e - порядок.
В нашем случае (то есть в случае вычислительных машин) основание почти всегда равно 2 (на деле это иногда не так, но в рамках этого приложения мы это не будем рассматривать).
Мантисса - это часть представления вещественного числа, которая составляет его старшие байты.
Порядок - это степень основания, в нашем случае - это степень двойки.
Вообще говоря, сколько бит использовать под мантиссу - не регламентируется этим представлением. Поэтому, теперь можно раскрыть тайну названия "плавающая точка" - она действительно "плавающая", так как при разном количестве бит под мантиссу, число будет представляться по-разному.
Так вот, к ответу на вопрос о рациональных числах - теперь уже слова из мануала:
Цитата:
Кроме того, рациональные числа, которые могут быть точно представлены в виде чисел с плавающей точкой с основанием 10, например, 0.1 или 0.7, не имеют точного внутреннего представления в качестве чисел с плавающей точкой с основанием 2, вне зависимости от размера мантиссы. Поэтому они и не могут быть преобразованы в их внутреннюю двоичную форму без небольшой потери точности. Это может привести к неожиданным результатам: например, floor((0.1+0.7)*10) скорее всего вернет 7 вместо ожидаемого 8, так как результат внутреннего представления будет чем-то вроде 7.9999999999999991118....
- не будут казаться непонятными. Итог - рациональные числа так же, как и иррациональные, в большинстве своем будут представляться неточно.
О практическом применении
Что это значит? То, что некоторые операции на типе данных float не будут выполняться корректно. Самый яркий пример - сравнение. Действительно, если все представляется приближенным, то речи о сравнении на равенство быть не может. Вместо этого обычно вводят константу, равную допустимой разнице между двумя значениями - допустимой для того, чтобы считать их равными. пример: