Web студия "GrandView"
  Главная   Написать Контакты
   
   
О проекте
Руководство php
 

Числа с плавающей точкой

Числа с плавающей точкой (они же числа двойной точности или действительные числа) могут быть определены при помощи любого из следующих синтаксисов:

<?php
$a
= 1.234;
$b = 1.2e3;
$c = 7E-10;
?>

Формально:

LNUM          [0-9]+
DNUM          ([0-9]*[\.]{LNUM}) | ({LNUM}[\.][0-9]*)
EXPONENT_DNUM ( ({LNUM} | {DNUM}) [eE][+-]? {LNUM})

Размер целого зависит от платформы, хотя максимум, как правило, ~1.8e308 с точностью около 14 десятичных цифр (это 64-битный IEEE-формат).

Точность числа с плавающей точкой

Довольно часто простые десятичные дроби вроде 0.1 или 0.7 не могут быть преобразованы в свои внутренние двоичные аналоги без небольшой потери точности. Это может привести к неожиданным результатам: например, floor((0.1+0.7)*10) скорее всего возвратит 7 вместо ожидаемой 8 как результат внутреннего представления числа, являющегося в действительности чем-то вроде 7.9999999999....

Это связано с невозможностью точно выразить некоторые дроби в десятичной системе счисления конечным числом цифр. Например, 1/3 в десятичной форме принимает вид 0.3333333. . ..

Так что никогда не доверяйте точности последних цифр в результатах с числами с плавающей точкой и никогда не проверяйте их на равенство. Если вам действительно необходима высокая точность, вам следует использовать математические функции произвольной точности или gmp-функции.

Преобразование в число с плавающей точкой

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



Строки> <Целые
Last updated: Sat, 27 Jan 2007
 
add a note add a note User Contributed Notes
Числа с плавающей точкой
helly at php dot net
22-Oct-2007 12:10
Floating point values have a limited precision. Hence a value might not have the same string representation after any processing. That also includes writing a floating point value in your script and directly printing it without any mathematical operations.

If you would like to know more about "floats" and what IEEE 754 is read this: http://docs.sun.com/source/806-3568/ncg_goldberg.html
sinuhet
14-Nov-2006 08:04
<?php
        define
('EPSILON', 1.0e-8);

        function
real_cmp($r1, $r2)
        {
               
$diff = $r1 - $r2;

                if(
abs($diff) < EPSILON )
                        return
0;
                else
                        return
$diff < 0 ? -1 : 1;
        }

        function
real_lt($r1, $r2)
        {
                return
real_cmp($r1, $r2) < 0;
        }

        echo
"raw compare\n";

       
$n = 0;
        for(
$i = 0.1; $i < 1.0; $i += 0.1) {
               
$n++;
                echo
"$i\t$n\n";
        }

        echo
"\nepsilon compare\n";

       
$n = 0;
        for(
$i = 0.1; real_lt($i, 1.0); $i += 0.1) {
               
$n++;
                echo
"$i\t$n\n";
        }

/*
        Outputs:

        raw compare
        0.1     1
        0.2     2
        0.3     3
        0.4     4
        0.5     5
        0.6     6
        0.7     7
        0.8     8
        0.9     9
        1       10

        epsilon compare
        0.1     1
        0.2     2
        0.3     3
        0.4     4
        0.5     5
        0.6     6
        0.7     7
        0.8     8
        0.9     9
*/
?>

So moral of this program? "Never compare floating point numbers for equality" solves only half of the problem. As seen above, even raw comparing of floats for less than (or grater than) is dangerous and epsilon (round, etc.) must be used.
TAS
27-Jul-2006 04:02
An update regarding the james dot cridland at virginradio dot co dot uk note below, I recently tried his formula using PHP 5 and it is necessary to specify the integer precision when using the round function, otherwise the output will be 0.

<? echo round((69.1-floor(69.1))); ?> // prints 0
<? echo round((69.1-floor(69.1)), 1); ?> // prints 0.1

Also, it appears that "small numbers" include everything up to 64.0.  So that

<? echo (63.1-floor(63.1)); ?>

will print 0.1 and

<? echo (64.0-floor(64.0)); ?>

will print 0, but

<? echo round(64.1-floor(64.1)); ?>

will print 0.099999999999994.
david at davidmosesNO dot SPAM dot ca
25-Mar-2006 01:48
Re: rick at ninjafoo dot com

There is no need to “always” use the BCMath functions. We just need to heed the documentation and “never compare floating point numbers for equality”.

The reason (19.6*100) !== (double)1960, is because inside a computer they are not equal.

Try this:

<?php

printf
("%.15f", (19.6*100));

?>

Outputs: 1960.000000000000227 (not 1960 as somewhat expected)

If comparison is required a few options come to mind (other than BCMath):

1) Round numbers before comparison:

<?php

$sig_figs
= 5;
echo (
round((19.6*100), $sig_figs) !== round((double)1960, $sig_figs)) ? 'not equal' : 'equal';

?>

Outputs: equal

2) Another method is to use a tolerance value, and consider numbers equal if their difference is less than the tolerance.
justin at jennnixon dot com
21-Nov-2005 04:00
I was playing around with a benchmark script:

<?php

$st
= array_sum (explode (' ', microtime ()));

ob_start ();

for (
$i = 1; $i < 10000; $i++) {
    echo
"<!-- Hello, World! " .  ($i % round(sqrt($i*2))) ^ $i " -->\n";
}

ob_end_flush ();

echo
round ((array_sum (explode (' ',microtime ())) - $st), 5) . "\n";

?>

Be careful with numbers, they can print out inpredictable things.  (For example, this printed out [uncommented])...
&#6410;
Новости
11 июля 2007
Сайт запущен
© 2007 info@grandviewstudio.com
Z058440144362 Z348613067571