расчет php дает странный результат для 1500000-20%

Может быть, я могу быть слепым или глупым, но посмотрите на мою функцию:

function max_min_twenty($value) {
if ((int)$value == 0) {
    return "0"; 
} else {
    $percent_val = ((int)$value / 100) * 20;
    $maxvalue = (int)$value + $percent_val;
    $minvalue = (int)$value - $percent_val;
    $returnvalue = round($minvalue)."-".round($maxvalue);
    return $returnvalue;
}
}

Кажется, это действительно легко! Это работает так, как должно, но если мое $value равно 1500000, оно возвращает мне 1,2E+6 для $minvalue — все работает хорошо если я выберу другое число или изменю процент на 19 или 21. Что это?

Он работает на PHP версии 5.2.4-2ubuntu5.27.


person maisch    schedule 15.06.2013    source источник


Ответы (3)


Отформатировать число явно как целое число? round возвращает число с плавающей запятой, и поэтому я считаю, что форматирование по умолчанию "запутывается" или "попадает в крайний случай" и возвращается к отображению научной нотации. (Я не могу вызвать проблему на ideone — это может быть связано с конкретной версией/средой PHP, но симптомы подходят)

Попробуйте sprintf:

return sprintf("%d-%d", $minvalue, $maxvalue);

(Я удалил round, так как %d заставляет аргументы обрабатываться как целые числа; однако могут быть тонкие различия в правилах округления.. Я не знаю.)

person user2246674    schedule 15.06.2013
comment
Что ж, метод sprintf, безусловно, решил проблему - СПАСИБО! Но все же остается вопрос, почему он сломался только с 1500000 на 20%. До какого предела это может дойти? Может быть, это поможет мне узнать это тоже ;-) - person maisch; 15.06.2013
comment
@maisch Я не уверен - я пытался воспроизвести здесь ideone.com/ZJmVWd, но не смог. Возможно, расчет эпсилон-дельта достаточно высок, чтобы правила по умолчанию рассматривали его как нецелое число. (Значения мантиссы с плавающей запятой, такие как float, не могут точно представлять все возможные целые числа в пределах своего диапазона.) - person user2246674; 15.06.2013

попробуйте использовать number_format

function max_min_twenty($value) {
if ((int)$value == 0) {
    return "0"; 
} else {
    $percent_val = ((int)$value / 100) * 20;
    $maxvalue = (int)$value + $percent_val;
    $minvalue = (int)$value - $percent_val;
    $returnvalue = number_format(round($minvalue),"0","-","")."-   ".number_format(round($maxvalue),"0","-","");
    echo $returnvalue;
}
}

он изменил научную запись на стандартную форму.

person shark    schedule 15.06.2013

Вы видите ошибочное поведение в старых версиях PHP. Это была ошибка №43053, которая была устранена в PHP 5.3.0.

Возьмем, к примеру, этот код:

for ($i = 1000000; $i < 2000000; $i += 100000)
    echo round($i) . "--\n";

В PHP 5.2.6 и ниже он создает следующий (пример; не может гарантировать, что CodePad всегда использовать старый PHP):

1000000--
1100000--
1.2E+6--
1300000--
1.4E+6--
1500000--
1600000--
1.7E+6--
1800000--
1.9E+6--

Однако на PHP 5.3.0 и выше можно увидеть правильное поведение:

1000000--
1100000--
1200000--
1300000--
1400000--
1500000--
1600000--
1700000--
1800000--
1900000--

Это можно исправить, обновив PHP или избегая round(), как предлагает @user2246674 в своем ответе.

person Eric    schedule 15.06.2013
comment
Похоже, что ошибка существует без раунда (пока это значение float). Хорошая находка :D - person user2246674; 15.06.2013
comment
Теперь я понимаю! Спасибо за объяснение. Теперь я использовал раунд в функции sprintf, и это отлично работает для меня. - person maisch; 15.06.2013