Подводные камни PHP

12 3
D
На сайте с 05.06.2007
Offline
155
2967

Вот удалось открыть чудо для себя.


$str1=10.20*100;
$str2=(int)$str1;
$str3=floor(10.20*100);
echo "$str1 $str2 $str3";

данный код выведет

1020 1019 1019


$str1=10.30*100;
$str2=(int)$str1;
$str3=floor(10.30*100);
echo "$str1 $str2 $str3";

за то этот выведет

1030 1030 1030

PHP 5.2.16/5.2.17 , в чём прикол?

Глюки в памяти? Баг php?

Написал не мало шедевров ;)
Anamnado
На сайте с 08.02.2010
Offline
242
#1

округление работает (выж дробь к целочисленному приводите)

почитайте правила округления

бага нет.

---------------------------------------------------------------------------------

хотя да - почему то такое тока при 10.20 а при 1.2 уже нормально - странноо ))

Anamnado добавил 09.02.2011 в 01:24

но ведь вот так правильно будет

<?php

$str1=10.2*100;

$str2=(float)$str1;

$str3=floor(10.2*100);

echo "$str1 $str2 $str3";

значит дело в округлении.. имхо )..

dkameleon
На сайте с 09.12.2005
Offline
386
#2
Dimanych:
Глюки в памяти? Баг php?

особенности хранения и обработки дробных чисел в бинарных системах.

Дизайн интерьера (http://balabukha.com/)
D
На сайте с 05.06.2007
Offline
155
#3

Anamnado ну а 3я строка ведь не верна!

Как минимум баг, в 5.3 тоже, посмотрите внимательно.

10.2*100 = 1020, оно так и выводится

Может оно в памяти и как float, но математически и визуально 1020

если уже целое число сделать ещё раз целым (int)1020, почему оно становится таким? 1019

Почему только на некоторые числа такое воздействие, где логическое объяснение?)

Учитывая действие floor, системно ошибку я вижу примерно так: 10.2*100 = 1019.99999999

Это баг привидения чисел, если писать код на Си, такого не возникнет.

Dimanych добавил 09-02-2011 в 15:41

Python подтвердил моё опасение...

>>> str = 10.20*100

>>> str

1019.9999999999999

>>> str = int(str)

>>> str

1019

>>> import math

>>> math.floor(10.20*100)/100

10.19

Это что на всех языках так?

Boris A Dolgov
На сайте с 04.07.2007
Offline
215
#4

Это называется "проблемы при работе с числами с плавающей запятой и их представлением в компьютере".

Дело в том, что числа хранятся в двоичной системе счисления в виде мантиссы (кроме первой цифры) и порядка. Некоторые числа (например, 0.2, 0.4, 0.6, 10.20) нельзя представить в виде конечной двоичной дроби, так как их запись - периодична. Из-за этого возникает погрешность округления. Наиболее хорошо это показывает командная строка питона:

>>> 0.4

0.40000000000000002

>>> 0.6

0.59999999999999998

Но добрые математики придумали решение проблем с округлением и кучей девяток - перед округлением достаточно прибавлять к округляемому что-то очень маленькое, и решать этим проблему:

>>> eps=1e-9

>>> floor(10.20*100)

1019.0

>>> floor(10.20*100 + eps)

1020.0

Вроде как даже проходят в школе :)

С уважением, Борис Долгов. Администрирование, дешевые лицензии ISPsystem, Parallels, cPanel, DirectAdmin, скины, SSL - ISPlicense.ru (http://www.isplicense.ru/?from=4926)
Anamnado
На сайте с 08.02.2010
Offline
242
#5
Dimanych:
Anamnado
1019.9999999999999

да я об этом сразу и подумал - но не знаю почему так.

Boris A Dolgov, вот наверно лучше знает )))

D
На сайте с 05.06.2007
Offline
155
#6

Ну вот блин, плохо быть самоучкой :)

Я считаю что это как то должно решаться на системном уровне, а не руками программиста :)

http://xpoint.ru/know-how/Articles/FloatingPointNumbers?comments

M
На сайте с 16.09.2009
Offline
278
#7
Dimanych:
Я считаю что это как то должно решаться на системном уровне, а не руками программиста :)

Что конкретно Вы решать предлагаете? Отменять правила математики? Считать напрямую в десятичной арифметике?

Dimanych:
http://xpoint.ru/know-how/Articles/FloatingPointNumbers?comments

Ошибки только кажет.

Абонементное сопровождение серверов (Debian) Отправить личное сообщение (), написать письмо ().
Алексей Барыкин
На сайте с 04.02.2008
Offline
272
#8
Dimanych:
Ну вот блин, плохо быть самоучкой :)
Я считаю что это как то должно решаться на системном уровне, а не руками программиста :)

http://xpoint.ru/know-how/Articles/FloatingPointNumbers?comments

Приказом президента Российской Федерации на период кризиса считать число Пи равным тройке!

D
На сайте с 05.06.2007
Offline
155
#9

Ух, началось, вы хоть вдумайтесь прежде чем писать!

После 10.20*100, PHP выводит целое число, если оно его выводит, почему бы сразу не представить его в памяти именно целым 1020? PHP ведь всё равно меняет типы на лево и на право. Зачем этот изврат конфликтов? И не умрёт интерпретатор поправив этот косяк ;)

Либо выводить уже как и питон, что подчёркивает этот бинарный глюк, либо править по факту.

M
На сайте с 16.09.2009
Offline
278
#10
Dimanych:
После 10.20*100, PHP выводит целое число

Два. Строку символов он выводит, а не число.

А вот в $str1 - у Вас действительно "число" в формате с плавающей точкой (посмотрите var_dump(), например). Use printf, Luke.

Dimanych:
PHP ведь всё равно меняет типы на лево и на право.

"Не налево и направо", а во вполне определенных случаях. Документацию будем читать?

Вообще, в там есть жырный warning, в деталях описывающий именно Вашу ситуацию (см. http://ru.php.net/manual/en/language.types.float.php). "Проглядеть" такое можно только по одной причине - если в документацию не смотреть. Вообще.

Dimanych:
Либо выводить уже как и питон, что подчёркивает этот бинарный глюк, либо править по факту.

Это не глюк, а арифметика.

12 3

Авторизуйтесь или зарегистрируйтесь, чтобы оставить комментарий