2011-01-23 3 views
3

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

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

Благодаря

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 

Я не знаю, что t все, что происходит в PHP.

Благодарности

+0

Необходимо указать код. – erjiang

+1

Возможный дубликат [Точность вычисления PHP float] (http://stackoverflow.com/questions/3957705/the-accuracy-of-php-float-calculate) и сотни других вариантов по этому вопросу –

+0

Вы должны указать код прямо сейчас. И расскажите, как они отличаются, каковы результаты и что вы ожидаете. (Также: PHP реализован в C, он, возможно, использует C-двойники под капотом.) – delnan

ответ

3

ограниченной точности форматов с плавающей точкой, почти всегда немного неточны, и эти неточности могут усугублять друг друга и проявляются в самых неожиданных направлениях. Обычно результаты не так уж ошибочны, но единственная проблема заключается в том, что вы не ожидали неточностей. Для общего объяснения см. The Floating-Point Guide.

Возможно, наиболее актуальным для вашего вопроса является то, что последовательности вычислений должны никогда не ожидать, чтобы получить одинаковые результаты на разных платформах, поскольку существует множество факторов, которые могут привести к выполнению различных реальных примитивных операций. This paper explains it in great detail..

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

+0

, но вычисления одинаковы в PHP и C, PHP был написан на C, поэтому я ожидал бы тех же результатов. –

+1

@ Карл: хорошо, ваши ожидания ошибочны. Это происходит с арифметикой с плавающей запятой. Взгляните на документ, к которому я привязался. –

+0

Мое правило: никогда не доверяйте вычислениям с плавающей запятой в вашей жизни;) Все арифметические операции с плавающей точкой являются неточными. Это неотъемлемое ограничение представления десятичного числа двоичному. Это влияет на ВСЕ языки программирования (а не только на PHP и C), это всего лишь вопрос о том, сколько бит они могут дать, прежде чем столкнуться с этим ограничением. Руководство по плавающей точке действительно отлично читается. –

2

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

printf("%.8f\n", bstar); 
+0

См. Новый код –

+0

Я могу подтвердить ответ Оли. –

+0

@ Карл, покажите нам printf, который вы используете. Если вы делаете% .8f, вы увидите только 8 цифр после десятичной точки. Результатом вычисления является что-то * 10^-9, которое потребует использования большего количества цифр в строке формата printf. –

0

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

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

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

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

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

References - MySQL Performance Blog