Странное и неожиданное поведение PHP | Floating Point

Floating Point неожиданное поведение PHP

Нет никаких сомнений: PHP является простым, мягким и прощающим языком. А еще, он может проявлять некоторое неожиданное поведение. Рассмотрим некоторые «странные факты» и почему PHP даёт такие результаты.

Плавающая точка неточности

Большинство знают, что числа с Floating Point (плавающей точкой) не могут отобразить все реальные действительные числа. Кроме того, некоторые операции между двумя хорошо представленными числами могут привести к неожиданным ситуациям. Это, потому что, результат, который компьютеры отображают это цифры и это влияет не только на PHP, но и все языки программирования. С плавающей точкой неточности появились  у программистов проблемы.

Об этом много говорили, и самое главное, каждый ученый, должен знать  арифметику Floating Point . Если никогда не читали, прочтите обязательно.

Посмотрим на этот очень маленький фрагмент:



<php echo (int) ((0.1 + 0.7) * 10);


Как вы думаете, какой будет результат? Если вы думаете что будет 8, то вы ошиблись … Этот код будет на самом деле печатать 7! Для тех, у кого есть Zend Certification, этот пример уже известен. Вы можете найти его в « Zend PHP 5 Руководство по изучению сертификации» .

Теперь давайте посмотрим, почему это происходит. Первая операция выполняет это:



0.1 + 0.7 // результат: 0,79999999999


В результате арифметическое выражения хранится внутри как 0.7999999, а не 0,8 в связи с точностью вопроса, и именно здесь начинаются проблемы.
Вторая операция выполняет это:



0.79999999 * 10 = 7,999999999


Эта операция работает хорошо, но сохраняет ошибки.

Третья и последняя операция выполняет это:



(int) 7,9999999 // результат равен 7


Результат явно округлённый. Когда значение преобразовывается в  int , PHP обрезает период, и получается целое число 7.

Существует две интересные вещи, которые нужно отметить:

  • Если вы скинули номера для float, а не для int, вы получите число 8
  • Процесс об этом не знает, и мы на самом деле получили эту ошибку из-за своей неточности, он работает, соответственно, парадокс математики, который утверждает что 0,999… равен 1 .

В заключение об этом, хотелось бы напомнить о  Zend PHP 5 Certification Учебное пособие Second Edition  :

Всякий раз, когда точность ваших расчетов является важным фактором для нормального функционирования вашего приложения, вы должны рассмотреть возможность использования (sic!) произвольная функция точности предоставляется расширением BCMath (вы можете найти его в Руководстве по PHP) вместо РНР встроенные типы данных.

Строка PHP «Increments»

Если в вашей повседневной работе вы пишите инструкции, которые выполняют увеличение или уменьшение операций, таких как эти:



<php $a = 5;
$b = 6;
$a++;
++$b;


Тут всё понятно, что происходит с этими заявлениями. Но, учитывая утверждение, что будет на выходе:



<php $a = 1;
$b = 3;
echo $a++ + $b;
echo $a + ++$b;
echo ++$a + $b++;


Давайте, их все проверим.



4  6  7


Не слишком сложно, не так ли? Теперь давайте немного усложним. Вы никогда не пробовали, увеличить строку? Попробуйте угадать, какой будет выход для следующих целей:



<php $a = 'fact_2';
echo ++$a;

$a = '2nd_fact';
echo ++$a;

$a = 'a_fact';
echo ++$a;

$a = 'a_fact?';
echo ++$a;


На этот раз, не так легко. Давайте раскроем ответы.



fact_3
2nd_facu
a_facu
a_fact?


Удивлены? Использование оператора инкремента на строку, заканчивающуюся числом и имеет эффект увеличения буквы (в алфавитном порядке, например, T -> U). Независимо, если строка начинается с цифры или нет, последний символ изменится. Но нет никакого эффекта, если строка заканчивается не буквенно-цифровыми символами.

Это хорошо документировано в официальной документации об  увеличение или уменьшение операторов , но большинство из вас, возможно, не читали, потому что вы, вероятно, думали, ничего особенного нет. Я должен признаться, я тоже так думал, до недавнего времени.

PHP образом Perl Конвенции при работе с арифметических операций с символьными переменными, не C. Например, в PHP и Perl $a = ‘Z’; $a++; обращается * в ‘AA’, в то время как в C a = ‘Z’; a++; превращается в ‘[‘ (ASCII значение ‘Z’ — 90, ASCII значение ‘[‘ 91). Обратите внимание, что символ переменные могут быть увеличены, но не уменьшается и даже так только ASCII символы (a-z и A-Z) поддерживаются. Увеличение или уменьшение прочих символов переменных не имеет никакого эффекта, исходная строка не изменяется.

Тайна значений

Вы уже знаете все о том, как создавать, управлять и удалять массивы. Тем не менее, следующий пример может вас удивить на первый взгляд.

Часто при работе с массивами и нужно искать, если данное значение в массиве. PHP имеет функцию для этого,  in_array() . Давайте посмотрим это в действии:



<php $array = array(   'isReady' => false,
  'isPHP' => true,
  'isStrange' => true
);
var_dump(in_array('phpmaster.com', $array));


Что будет на выходе? Делайте ваши ставки, и давайте проверим.



true


Не является ли это немного странным? У нас есть ассоциативный массив, где ее значения все логические и если мы будем искать строку, мы получили истинное. Имеет это значение волшебно появился? Давайте посмотрим еще один пример.



<php $array = array(   'count' => 1,
  'references' => 0,
  'ghosts' => 1
);
var_dump(in_array('aurelio', $array));


И то, что мы получаем …



true


Еще раз  in_array()  возвращает true . Как это возможно?

Вы испытываете один из двух лучших и худших, любили и ненавидели PHP функций. PHP не строго типизированных и где начинается ошибка. На самом деле, все следующие значения, если сравнивать PHP, считаются одинаковыми, если вы используете единичный оператор:

  • 0
  • false
  • «»
  • «0″
  • NULL
  • array()

По умолчанию, функция in_array()  использует свободные сравнения, не пусто («» и non-zero-filled («0″) string равна true , а для всех ненулевых цифр (например, 1). Следовательно, в первом примере мы получили true , потому что 'pixel.com' == true , то во втором у нас есть 'pixel.com' == 1 .



<php $array = array(   'count' => 1,
  'references' => 0,
  'ghosts' => 1
);
var_dump(in_array('aurelio', $array, true));


мы, наконец, получим  false , как мы ожидали!

Заключение

В этой статье вы видели странное и неожиданное поведение которое может возникнуть у вас при использовании PHP. Вывод из этих примеров:

  • Никогда не доверяйте числам с плавающей точкой
  • Дважды проверьте, какой тип данных сначала вы использовали в операции
  • Будьте осведомлены о проблемах свободных сравнений и свободные типы данных

А главное, никогда не забывайте что компьютер начинает считать с нуля! Если вы продвинутый пользователь, то вы, вероятно, уже это всё знали, но переподготовка никогда не бывает бесполезной.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *


+ 3 = 6

Можно использовать следующие HTML -теги и атрибуты: <a href= http://pixelcom.crimea.ua/"" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>