Почему PHP float и POW дают неверные и неожиданные результаты? - PullRequest
3 голосов
/ 24 января 2011

Кто-нибудь знает, почему это происходит и можно ли это исправить. Я сравниваю результаты C и PHP, но PHP дает мне разные результаты.

Я могу предоставить код, если это необходимо, но кто-нибудь сталкивался с этим раньше?

PHP код

$tempnum = 1.0e - 5 * -44954; // substr($line1,53,6);
$bstar = $tempnum / pow(10.0, 3);

$bstar gives me -0.00044954 in PHP but it should be -0.000450

код C

double tempnum = 1.0e - 5 * -44954;
double bstar = tempnum / pow(10.0, 3);

printf bstar gives me -0.000450

Спасибо за ваши ответы, но как PHP пришел к такому выводу ...

$twopi =        6.28318530717958623;    /* 2*Pi  */
$xmnpda=        1440; //1.44E3  ;       /* Minutes per day */

$temp = (($twopi/$xmnpda)/$xmnpda);

$xndt2o = -0.000603;
$xndt2o = $xndt2o * $temp;

echo $xndt2o gives me -1.8256568188E-9 in PHP but in C it gives me -0.000000

Я не знаю, что все это значит в PHP.

Ответы [ 3 ]

3 голосов
/ 24 января 2011

Форматы с плавающей запятой с ограниченной точностью почти всегда немного неточны, и эти неточности могут объединять друг друга и проявляться неожиданными способами.Обычно результаты не так уж и неправильны, но единственная проблема в том, что вы не ожидали неточностей.Для общего объяснения прочитайте Руководство с плавающей точкой .

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

Гораздо более простое объяснение разницы, которую вы видите, может заключаться в том, что код PHP каким-то образом использует где-то только 32-битное значение с плавающей точкой, потомуРазница проявляется вокруг 6-го / 7-го знака после запятой, где заканчивается точность 32-битных операций с плавающей запятой.

2 голосов
/ 24 января 2011

Эквивалентный код C дает тот же результат, если вы скажете printf отображать больше цифр:

printf("%.8f\n", bstar);
0 голосов
/ 24 января 2011

Большое спасибо за вашу помощь, ребята.Я понял это.

Иногда вам нужно работать с большими числами в PHP.Например, иногда 32-разрядных идентификаторов недостаточно, и вы должны использовать BIGINT 64-разрядный.

Я уже писал о беспорядке, что 64-разрядные целые числа находятся в PHP.Но если числа, которые вы используете, не полностью покрывают 64-битный диапазон, плавающие числа могут спасти день.Хитрость в том, что PHP-плавающие числа на самом деле удваиваются, то есть 64-битные числа с двойной точностью.У них есть 52 бита для мантиссы, и целые значения до 2 ^ 53-1 могут быть сохранены точно.Так что, если вы используете до 53 битов, вы в порядке с плавающей точкой.

Однако есть предостережение о конвертации, о котором вы должны знать.

Преобразование с плавающей точкой в ​​строку не переносимосистемы и версии PHP.Поэтому, если вы обрабатываете большие числа, хранящиеся как float (особенно в 32-битных системах, где 32-битное int-переполнение неявно преобразуется в float), и получаете странные результаты, помните, что преобразование строк может вас подвести.sprintf (), с другой стороны, всегда дружит, когда дело доходит до исправления «тонкостей» PHP при обработке числовых значений: его можно использовать для обхода проблем со знаком и без знака в int;это помогает с форматированием поплавка;всегда спаситель.

Ссылки - MySQL Performance Blog

...