Округление чисел в PHP
Округление числа в любом языке программирования может быть выполнено до целого числа или до заданного количества знаков после запятой. Кроме того, учитывается еще, в какую сторону округляется число – к большему или меньшему значению, а так же математически в ближайшую сторону.
В PHP для округления чисел применяются следующие функции:
— round – округление до ближайшего значения;
— ceil – округление до ближайшего значения в большую сторону;
— floor – округление до ближайшего значения в меньшую сторону.
Округление до целого числа
Все функции в качестве основного параметра используют значение с плавающей точкой. Например:
При выполнении каждой функции, получим следующие значения:
При математическом округлении, учитывается значение числа округляемой части. Если оно меньше 5, округляется к меньшему. Если равно или больше 5, округление будет выполнено в большую сторону. В данном случае функция round округляет к меньшему значению, т.к. значение дробной части меньше 0.5. Если использовать значение больше, например:
В результате округления, получим:
Округление числа до заданного количества знаков после запятой
Для такого округления чисел используется только функция round, имеющая второй (не обязательный) параметр, определяющий точность округления. Задав его можно получить необходимое количество знаков после запятой:
Другие примеры округления
Если вдруг потребовалось реализовать более экзотическое округление – к большему или меньшему значению с заданным количеством знаков после запятой, потребуются дополнительные операции. Как было сказано выше, функции ceil и floor имеют только один параметр и не смогут округлить число до заданной точности.
В таких случаях можно выполнить умножение числа, чтобы затем округлить нужным способом. Например, число нужно округлить до большего значения с двумя знаками после запятой:
В результате получим 123.84, хотя аналогичное округление функцией round> в данном случае вернуло бы 123.83.
Так же можно поступить, если нужно округлить до меньшего значения с заданной точностью:
round
Возвращает округлённое значение num с указанной точностью precision (количество цифр после запятой). precision может быть отрицательным или нулём (по умолчанию).
Список параметров
Значение для округления.
Количество десятичных знаков, до которых производится округление
Если precision положительный, num округляется до точности precision цифр после запятой.
Если precision отрицателен, num округляется до точности precision цифр перед десятичной запятой, то есть до ближайшего кратного pow(10, -precision) , например для precision равной -1 num округляется до десятков, для precision равной -2 до сотен и т.д.
Используйте одну из этих констант для задания способа округления.
| Константы | Описание |
|---|---|
| PHP_ROUND_HALF_UP | Округляет num от нуля, когда следующий знак находится посередине. То есть округляет 1.5 в 2 и -1.5 в -2. |
| PHP_ROUND_HALF_DOWN | Округляет num к нулю, когда следующий знак находится посередине. То есть округляет 1.5 в 1 и -1.5 в -1. |
| PHP_ROUND_HALF_EVEN | Округляет num до ближайшего чётного значения, когда следующий знак находится посередине. То есть округляет 1.5 и 2.5 в 2. |
| PHP_ROUND_HALF_ODD | Округляет num до ближайшего нечётного значения, когда следующий знак находится посередине. То есть округляет 1.5 в 1 и 2.5 в 3. |
Возвращаемые значения
Значение округляется до заданного значения precision как float .
Список изменений
| Версия | Описание |
|---|---|
| 8.0.0 | num больше не принимает внутренние объекты, поддерживающие числовое преобразование. |
Примеры
Пример #1 Пример использования round()
Результат выполнения данного примера:
Пример #2 Как параметр precision влияет на числа с плавающей точкой
var_dump ( round ( $number , 3 ));
var_dump ( round ( $number , 2 ));
var_dump ( round ( $number , 1 ));
var_dump ( round ( $number , 0 ));
var_dump ( round ( $number , — 1 ));
var_dump ( round ( $number , — 2 ));
var_dump ( round ( $number , — 3 ));
?>
Результат выполнения данного примера:
Пример #3 Примеры использования параметра mode
<?php
echo ‘Режимы округления с 9.5’ . PHP_EOL ;
var_dump ( round ( 9.5 , 0 , PHP_ROUND_HALF_UP ));
var_dump ( round ( 9.5 , 0 , PHP_ROUND_HALF_DOWN ));
var_dump ( round ( 9.5 , 0 , PHP_ROUND_HALF_EVEN ));
var_dump ( round ( 9.5 , 0 , PHP_ROUND_HALF_ODD ));
echo PHP_EOL ;
echo ‘Режимы округления с 8.5’ . PHP_EOL ;
var_dump ( round ( 8.5 , 0 , PHP_ROUND_HALF_UP ));
var_dump ( round ( 8.5 , 0 , PHP_ROUND_HALF_DOWN ));
var_dump ( round ( 8.5 , 0 , PHP_ROUND_HALF_EVEN ));
var_dump ( round ( 8.5 , 0 , PHP_ROUND_HALF_ODD ));
?>
Результат выполнения данного примера:
Пример #4 Примеры использования параметра mode с указанием точности precision
<?php
echo ‘Использование PHP_ROUND_HALF_UP с точностью до 1 знака’ . PHP_EOL ;
var_dump ( round ( 1.55 , 1 , PHP_ROUND_HALF_UP ));
var_dump ( round (- 1.55 , 1 , PHP_ROUND_HALF_UP ));
echo PHP_EOL ;
echo ‘Использование PHP_ROUND_HALF_DOWN с точностью до 1 знака’ . PHP_EOL ;
var_dump ( round ( 1.55 , 1 , PHP_ROUND_HALF_DOWN ));
var_dump ( round (- 1.55 , 1 , PHP_ROUND_HALF_DOWN ));
echo PHP_EOL ;
echo ‘Использование PHP_ROUND_HALF_EVEN с точностью до 1 знака’ . PHP_EOL ;
var_dump ( round ( 1.55 , 1 , PHP_ROUND_HALF_EVEN ));
var_dump ( round (- 1.55 , 1 , PHP_ROUND_HALF_EVEN ));
echo PHP_EOL ;
echo ‘Использование PHP_ROUND_HALF_ODD с точностью до 1 знака’ . PHP_EOL ;
var_dump ( round ( 1.55 , 1 , PHP_ROUND_HALF_ODD ));
var_dump ( round (- 1.55 , 1 , PHP_ROUND_HALF_ODD ));
?>
Результат выполнения данного примера:
Смотрите также
- ceil() — Округляет дробь в большую сторону
- floor() — Округляет дробь в меньшую сторону
- number_format() — Форматирует число с разделением групп
User Contributed Notes 32 notes
In my opinion this function lacks two flags:
— PHP_ROUND_UP — Always round up.
— PHP_ROUND_DOWN — Always round down.
In accounting, it’s often necessary to always round up, or down to a precision of thousandths.
<?php
function round_up ( $number , $precision = 2 )
<
$fig = (int) str_pad ( ‘1’ , $precision , ‘0’ );
return ( ceil ( $number * $fig ) / $fig );
>
function round_down ( $number , $precision = 2 )
<
$fig = (int) str_pad ( ‘1’ , $precision , ‘0’ );
return ( floor ( $number * $fig ) / $fig );
>
?>
As PHP doesn’t have a a native number truncate function, this is my solution — a function that can be usefull if you need truncate instead round a number.
<?php
/**
* Truncate a float number, example: <code>truncate(-1.49999, 2); // returns -1.49
* truncate(.49999, 3); // returns 0.499
* </code>
* @param float $val Float number to be truncate
* @param int f Number of precision
* @return float
*/
function truncate ( $val , $f = «0» )
<
if(( $p = strpos ( $val , ‘.’ )) !== false ) <
$val = floatval ( substr ( $val , 0 , $p + 1 + $f ));
>
return $val ;
>
?>
Originally posted in http://stackoverflow.com/a/12710283/1596489
If you have negative zero and you need return positive number simple add +0:
$number = -2.38419e-07;
var_dump(round($number,1));//float(-0)
var_dump(round($number,1) + 0);//float(0)
I discovered that under some conditions you can get rounding errors with round when converting the number to a string afterwards.
To fix this I swapped round() for number_format().
Unfortunately i cant give an example (because the number cant be represented as a string !)
essentially I had round(0.688888889,2);
which would stay as 0.68888889 when printed as a string.
But using number_format it correctly became 0.69.
Excel-like ROUNDUP function:
public static function round_up($value, $places)
<
$mult = pow(10, abs($places));
return $places < 0 ?
ceil($value / $mult) * $mult :
ceil($value * $mult) / $mult;
>
echo round_up(12345.23, 1); // 12345.3
echo round_up(12345.23, 0); // 12346
echo round_up(12345.23, -1); // 12350
echo round_up(12345.23, -2); // 12400
echo round_up(12345.23, -3); // 13000
echo round_up(12345.23, -4); // 20000
Note that PHP 5.3 didn’t just introduce $mode, it rewrote the rounding implementation completely to eliminate many kinds of rounding errors common to rounding floating point values.
That’s why round() gives you the correct result even when floor/ceil don’t.
For example, floor(0.285 * 100 + 0.5) VS round(0.285*100 + 0.5). First one gives 28, second one gives 29.
Solving round_down() problem:
——————————
Use of <?php floor ( pow ( 10 , $precision ) * $value ) / pow ( 10 , $precision ); ?> fails in some cases, e.g. round_down(2.05, 2) gives incorrect 2.04.
Here is a «string» solution (https://stackoverflow.com/a/26491492/1245149) of the problem (a negative precision is not covered):
<?php
function round_down ( $value , $precision ) <
$value = (float) $value ;
$precision = (int) $precision ;
if ( $precision < 0 ) <
$precision = 0 ;
>
$decPointPosition = strpos ( $value , ‘.’ );
if ( $decPointPosition === false ) <
return $value ;
>
return (float)( substr ( $value , 0 , $decPointPosition + $precision + 1 ));
>
?>
Solving round_up() problem:
—————————
Use of <?php ceil ( pow ( 10 , $precision ) * $value ) / pow ( 10 , $precision ); ?> fails in some cases, e.g. round_up(2.22, 2) gives incorrect 2.23 (https://stackoverflow.com/a/8239620/1245149).
Adapting the above round_down() «string» solution I have got this result (a negative precision is not covered):
<?php
function round_up ( $value , $precision ) <
$value = (float) $value ;
$precision = (int) $precision ;
if ( $precision < 0 ) <
$precision = 0 ;
>
$decPointPosition = strpos ( $value , ‘.’ );
if ( $decPointPosition === false ) <
return $value ;
>
$floorValue = (float)( substr ( $value , 0 , $decPointPosition + $precision + 1 ));
$followingDecimals = (int) substr ( $value , $decPointPosition + $precision + 1 );
if ( $followingDecimals ) <
$ceilValue = $floorValue + pow ( 10 , — $precision ); // does this give always right result?
>
else <
$ceilValue = $floorValue ;
>
return $ceilValue ;
>
?>
I don’t know it is bulletproof, but at least it removes the above mentioned fail. I have done no binary-to-decimal-math-analysis but if `$floorValue + pow(10, 0 — $precision)` works
always as expected then it should be ok.
echo mround(34.89999); //34.90
If you’d only want to round for displaying variables (not for calculating on the rounded result) then you should use printf with the float:
<?php printf ( «%6.2f» , 3.39532 ); ?>
This returns: 3.40 .
Here is function that rounds to a specified increment, but always up. I had to use it for price adjustment that always went up to $5 increments.
<?php
function roundUpTo ( $number , $increments ) <
$increments = 1 / $increments ;
return ( ceil ( $number * $increments ) / $increments );
>
?>
Unexpected result or misunderstanding (php v5.5.9)
echo round ( 1.55 , 1 , PHP_ROUND_HALF_DOWN ); // 1.5
echo round ( 1.551 , 1 , PHP_ROUND_HALF_DOWN ); //1.6
/**
* Round to first significant digit
* +N to +infinity
* -N to -infinity
*
*/
function round1stSignificant ( $N ) <
if ( $N === 0 ) <
return 0;
>
$x = floor ( log10 ( abs( $N ) ) );
return ( $N > 0 )
? ceil( $N * pow ( 10, $x * -1 ) ) * pow( 10, $x )
: floor( $N * pow ( 10, $x * -1 ) ) * pow( 10, $x );
>
echo round1stSignificant( 39144818 ) . PHP_EOL;
echo round1stSignificant( 124818 ) . PHP_EOL;
echo round1stSignificant( 0.07468 ) . PHP_EOL;
echo round1stSignificant( 0 ) . PHP_EOL;
echo round1stSignificant( -0.07468 ) . PHP_EOL;
this function (as all mathematical operators) takes care of the setlocale setting, resulting in some weirdness when using the result where the english math notation is expected, as the printout of the result in a width: style attribute!
<?php
$a = 3 / 4 ;
echo round ( $a , 2 ); // 0.75
setlocale ( LC_ALL , ‘it_IT@euro’ , ‘it_IT’ , ‘it’ );
$b = 3 / 4 ;
echo round ( $b , 2 ); // 0,75
?>
This function will let you round to an arbitrary non-zero number. Zero of course causes a division by zero.
<?php
function roundTo ( $number , $to ) <
return round ( $number / $to , 0 )* $to ;
>
echo roundTo ( 87.23 , 20 ); //80
echo roundTo (- 87.23 , 20 ); //-80
echo roundTo ( 87.23 , .25 ); //87.25
echo roundTo ( .23 , .25 ); //.25
?>
Please note that the format of this functions output also depends on your locale settings. For example, if you have set your locale to some country that uses commas to separate decimal places, the output of this function also uses commas instead of dots.
This might be a problem when you are feeding the rounded float number into a database, which requires you to separate decimal places with dots.
See it in action:
<?php
echo round ( ‘3.5558’ , 2 );
setlocale ( constant ( ‘LC_ALL’ ), ‘et_EE.UTF-8’ );
echo ‘<br />’ . round ( ‘3.5558’ , 2 );
?>
The output will be:
3.56
3,56
Here’s a function to round to an arbitary number of significant digits. Don’t confuse it with rounding to a negative precision — that counts back from the decimal point, this function counts forward from the Most Significant Digit.
<?php
round ( 1241757 , — 3 ); // 1242000
RoundSigDigs ( 1241757 , 3 ); // 1240000
?>
Works on negative numbers too. $sigdigs should be >= 0
<?php
function RoundSigDigs ( $number , $sigdigs ) <
$multiplier = 1 ;
while ( $number < 0.1 ) <
$number *= 10 ;
$multiplier /= 10 ;
>
while ( $number >= 1 ) <
$number /= 10 ;
$multiplier *= 10 ;
>
return round ( $number , $sigdigs ) * $multiplier ;
>
?>
When you have a deal with money like dollars, you need to display it under this condition:
-format all number with two digit decimal for cents.
-divide 1000 by ,
-round half down for number with more than two decimal
I approach it using round function inside the number_format function:
number_format((float)round( 625.371 ,2, PHP_ROUND_HALF_DOWN),2,’.’,’,’) // 625.37
number_format((float)round( 625.379 ,2, PHP_ROUND_HALF_DOWN),2,’.’,’,’) // 625.38
number_format((float)round( 1211.20 ,2, PHP_ROUND_HALF_DOWN),2,’.’,’,’) // 1,211.20
number_format((float)round( 625 ,2, PHP_ROUND_HALF_DOWN),2,’.’,’,’) // 625.00
round() will sometimes return E notation when rounding a float when the amount is small enough — see https://bugs.php.net/bug.php?id=44223 . Apparently it’s a feature.
To work around this «feature» when converting to a string, surround your round statement with an sprintf:
sprintf(«%.10f», round( $amountToBeRounded, 10));
Here is a short neat function to round minutes (hour) .
function minutes_round ( $hour = ’14:03:32′ , $minutes = ‘5’ , $format = «H:i» )
<
// by Femi Hasani [www.vision.to]
$seconds = strtotime ( $hour );
$rounded = round ( $seconds / ( $minutes * 60 )) * ( $minutes * 60 );
return date ( $format , $rounded );
>
?>
You decide to round to nearest minute .
example will produce : 14:05
Функция PHP round — округляем быстро и просто
В этой статье мы рассмотрим PHP-функцию, с помощью которой можно выполнять такую математическую операцию, как округление числа. Также читатель узнает о нескольких режимах работы данной функции и возможных способах ее реализации. Для наилучшего понимания теория будет сопровождаться практическими примерами.
Чтобы округлить цифры, в языке программирования PHP используется известная функция round() . Если вы не новичок в изучении программирования, то данная функция может быть вам уже знакома. Если же ваш путь только начинается, то ознакомиться с её возможностями стоит обязательно, так как она является полезной и может пригодиться в работе.
Прежде чем продолжить, следует сказать, что в языке PHP предусмотрены три типа округления целого и дробного числа (в большую сторону, в меньшую сторону, а также по стандартному математическому правилу). Начнём с третьего типа. Здесь round() округляет значения по правилу, которое все проходили в школе. Давайте его вспомним: 1) если цифра, подлежащая округлению, находится в пределах 0-4, то цифра разряда, до которого осуществляется округление, не изменяется, а оставшиеся числа заменяются нулями; 2) если цифра, подлежащая округлению, находится в пределах 5-9, то цифра разряда, до которого осуществляется округление, повышается на единицу, а оставшиеся числа тоже заменяются нулями.
Исходя из вышесказанного, рассмотрим несколько практических примеров:
В результате работы этого кода на экран будет выведено целое число 5.
Идём дальше. Следующий пример выведет уже целое число 6, что отвечает правилу, написанному выше:
Также можно определить, до какого именно числа округлять значения. Для этого следует указать не только число, но и количество знаков, находящихся до запятой (количество знаков (символов), находящихся после запятой). Общий синтаксис предельно прост:
Рассмотрим на примере:
Вы можете проверить работу этого кода самостоятельно, используя простейший онлайн-компилятор.
Округляем в большую/меньшую сторону
Осталось рассмотреть, как округлять цифры в меньшую или большую сторону. Сделать это тоже несложно, но потребуется дополнительный третий параметр, называемый mode. Этот параметр нужен для передачи соответствующей константы. Речь идёт о специальных зарезервированных в языке константах, которые перечислены ниже: • PHP_ROUND_HALF_UP — используется, если надо округлить в большую сторону; • PHP_ROUND_HALF_DOWN — используется, если надо округлить в меньшую сторону.
Обязательно рассмотрим практические примеры работы констант:
Пожалуй, это всё, что можно рассказать о популярной функции round. Похожая функция используется в JavaScript и Java, правда, называется она Math.round (округляет до ближайшего целого: 2.1 превращается в два, 2.6 — в три, а -1.1 — в -1).
Это предельно простые операции, освоить которые не составит труда. Если же хотите получить действительно продвинутые знания по PHP-разработке, добро пожаловать на специализированный курс в OTUS!
Методы округления в Excel, PHP и не только
При решении задач мат.моделирования и автоматизации бизнес-процессов очень часто возникают погрешности результата, связанные с неочевидностью выбора способов округления, используемых при написании кода.
Так, заказчик почти никогда не может явно сформулировать требования к применяемым в расчетах способам округления, и, зачастую, просто использует расчет, выполненный в Excel-е, как эталон, не задумываясь, как именно и почему именно так происходит округление в том или ином случае.
В такой ситуации полезно:
- точно представлять существующие стандартные методы округления,
- уметь по расчету Excel или другому <эталонному> расчету определять использованные в нем методы округления,
- уметь воспроизводить желаемый способ округления средствами языка, используемого для разработки.
В данной статье мы расскажем о стандартных способах округления, проанализируем пакет MS Excel 2003, пакет OpenOffice Calc 2.3.0 и язык PHP на предмет имеющихся в них функций округления и их соответствия стандартным. Попутно будут предложены примеры реализаций недостающих функций.
Виды округлений
Стандарт IEEE 754 описывает семь методов округления чисел:
- round-down — усечение, округление по направлению к нулю,
- round-half-up — арифметическое округление (если отбрасываемые цифры больше либо равны 0.5, происходит округление вверх (от нуля), иначе цифры просто отбрасываются),
- round-half-even — банковское округление, (если отбрасываемые цифры больше 0.5, происходит округление вверх (от нуля), если меньше 0.5 — цифры отбрасываются, если отбрасываемая часть равна 0.5, то округление происходит в зависимости от четности предпоследней цифры),
- round-ceiling — округление к плюс бесконечности,
- round-floor — округление к минус бесконечности,
- round-half-down — подобно арифметическому (round-half-up), пятерка округляется вниз,
- round-up — округление от нуля.
Первые пять методов являются, согласно стандарту, обязательными к реализации, а последние два — опциональными.
Тестовая выборка, однозначно различающая методы
Для определения соответствия функции, реализующей округление, некоторому стандартному методу округления удобно воспользоваться специальной тестовой выборкой чисел. Предлагаемый набор из 4 чисел позволяет однозначно различить перечисленные в стандарте семь методов округления.
Рассмотрим следующую таблицу (в предположении, что округления производились до 1 знака после запятой):
Тип округления 0.35 -0.25 -0.41 -0.59 round_down 0,3–0,2–0,4–0,5 round_up 0,4–0,3–0,5–0,6 round_half_up 0,4–0,3–0,4–0,6 round_half_even 0,4–0,2–0,4–0,6 round_ceiling 0,4–0,2–0,4–0,5 round_floor 0,3–0,3–0,5–0,6 round_half_down 0,3–0,2–0,4–0,6
Не будем проводить доказательства того, что набор из 4 чисел является минимальным для решения задачи различения методов, покажем лишь, что в данном конкретном наборе нельзя удалить ни одно из чисел:
- При удалении числа 0.35 <склеиваются> методы round_half_even и round_half_down.
- При удалении числа -0.25 <склеиваются> методы round_half_up и round_half_even.
- При удалении числа -0.41 <склеиваются> методы round_up и round_half_up.
- При удалении числа -0.59 <склеиваются> методы round_half_even и round_ceiling.
Отметим, что данный набор чисел не может использоваться для доказательства корректности той или иной функции округления, а только для определения её типа и только в том случае, если заранее известно, что функция реализует один из 7 вышеописанных методов округления.
Анализ существующих функций округления в MS Excel 2003
Изучение и понимание отличий функций округления, доступных в MS Excel, представляется нам важной задачей, т.к. большинство расчетных прототипов, входящих в ТЗ на задачи автоматизации и моделирования, реализуются именно средствами MS Office. При этом важно понимать, что проверка корректности выполнения ТЗ обычно производится путем сверки результатов с результатами прототипа. Таким образом, умение воспроизводить результаты работы методов округления, используемых в каждом конкретном случае, является необходимыми для получения адекватных расчетных результатов.
Анализ справочника функций MS Office Excel 2003 позволяет составить следующий список стандартных функций, реализующих различные виды округления: ОКРУГЛ, ОКРВВЕРХ, ОКРВНИЗ, ОКРУГЛВВЕРХ, ОКРУГЛВНИЗ, ОТБР, ЦЕЛОЕ.
Функция 0.35 -0.25 -0.41 -0.59 Результат анализа ОКРУГЛ 0.4–0.3–0.4–0.6совпадает с round_half_up ОКРВВЕРХ 0.4–0.3–0.5–0.6совпадает с round_up ОКРВНИЗ 0.3–0.2–0.4–0.5совпадает с round_down ОКРУГЛВВЕРХ 0.4–0.3–0.5–0.6совпадает с round_up ОКРУГЛВНИЗ 0.3–0.2–0.4–0.5совпадает с round_down ОТБР 0.3–0.2–0.4–0.5совпадает с round_down ЦЕЛОЕ 0–1–1–1не позволяет использовать точность. ЦЕЛОЕ(X*10)/10 0.3–0.3–0.5–0.6совпадает с round_floor
Таким образом, получаем следующие различные наборы функций:
- ОКРУГЛ использует метод round_half_up,
- ОКРВВЕРХ, ОКРУГЛВВЕРХ используют round_up (различаются способом указания аргументов),
- ОКРВНИЗ, ОКРУГЛВНИЗ, ОТБР используют round_down (различаются способом указания аргументов),
- ЦЕЛОЕ использует round_floor, но не позволяет использовать точность.
Следовательно, пользователям MS Excel доступны 4 из 7 рассматриваемых методов округления:
- round_up (округление от нуля),
- round_down (округление к нулю)
- round_half_up (арифметическое округление),
- round_floor (округление к минус бесконечности).
Реализация недостающих методов округления в MS Excel 2003
Для реализации недостающих методов округления нам потребуется математическая функция sgn (signum). В языке формул MS Excel она реализована функцией ЗНАК.
Итак, опишем на псевдокоде, близком к языку формул MS Excel, формулы, позволяющие получить желаемые методы округления.
ROUND_CEILING (X,D) = ЕСЛИ(ЗНАК(X)>0;ОКРУГЛВВЕРХ(X;D);ОКРУГЛВНИЗ(X;D))
ROUND_FLOOR (X,D) = ЕСЛИ(ЗНАК(X)<0;ОКРУГЛВВЕРХ(X;D);ОКРУГЛВНИЗ(X;D))
ROUND_HALF_DOWN(X,D) = ЕСЛИ (2*ОКРУГЛВВЕРХ(X;D) = ОКРУГЛВВЕРХ(2* X;D);ОКРУГЛ(X;D);ОКРУГЛВНИЗ(X;D))
ROUND_HALF_EVEN(X,D) = ЕСЛИ (ОКРУГЛ(X;D) = ROUND_HALF_DOWN(X,D);ОКРУГЛ(X;D);ЕСЛИ( ОКРУГЛВНИЗ(X;D)/2 = ОКРУГЛВНИЗ(ОКРУГЛВНИЗ(X;D)/2;D); ОКРУГЛВНИЗ(X;D); ОКРУГЛВВЕРХ(X;D) ) )
Данные формулы не являются единственным или наилучшим способом реализации указанных методов округления, а являются лишь иллюстрацией возможности их реализации через имеющиеся стандартные методы MS Excel.
Сравнение округлений в OpenOffice Calc 2.3.0 и в MS Excel 2003
Изучение справочника функций языка формул OpenOffice Calc позволило составить такой список функций округления: TRUNC, ROUND, ROUNDDOWN, ROUNDUP, CEILING, FLOOR, MROUND, INT. При этом функции CEILING и FLOOR имеют 2 режима, один из которых (mode=1) декларирован как режим совместимости с MS Excel.
Функция 0.35 -0.25 -0.41 -0.59 Тип округления Соответстие в Excel TRUNC 0,3–0,2–0,4–0,5round_down ОТБР ROUND 0,4–0,3–0,4–0,6round_half_up ОКРУГЛ ROUNDDOWN 0,3–0,2–0,4–0,5round_down ОКРУГЛВНИЗ ROUNDUP 0,4–0,3–0,5–0,6round_up ОКРУГЛВВЕРХ CEILING (mode=0) 0,4–0,2–0,4–0,5round_ceiling Отустствует CEILING (mode=1) 0,4–0,3–0,5–0,6round_up ОКРВВЕРХ FLOOR (mode=0) 0,3–0,3–0,5–0,6round_floor Отсутствует FLOOR (mode=1) 0,3–0,2–0,4–0,5round_down ОКРВНИЗ MROUND 0,4–0,3–0,4–0,6round_half_up Отсутствует INT 0–1–1–1не позволяет использовать точностьЦЕЛОЕ INT(X*10)/10 0,3–0,3–0,5–0,6round_floor ЦЕЛОЕ(X*10)/10
Таким образом, OpenOffice Calc содержит больше различных функций округления, а именно функции CEILI NG и FLOOR, реализующие в режиме (mode=0) методы round_ceiling и round_floor, соответственно.
Анализ существующих функций округления в PHP
Спецификация языка PHP предлагает 4 способа округления чисел: intval, round, floor, ceil. Существуют также менее очевидные способы округления чисел в PHP путем форматирования числа в строку и преобразования его обратно в число. Для такого форматирования могут использоваться стандартные php-функции number_format и sprintf.
Поскольку функции ceil, floor и intval не позволяют указывать требуемую точность округления, для них были написаны обертки (соответственно, p_ceil, p_floor и p_intval).
Функция 0.35 -0.25 -0.41 -0.59 Результат анализа round 0.4–0.3–0.4–0.6совпадает с round_half_up ceil 1000не позволяет использовать точность floor 0–1–1–1не позволяет использовать точность intval 0000не позволяет использовать точность p_ceil 0.4–0.2–0.4–0.5совпадает с round_ceiling p_floor 0.3–0.3–0.5–0.6совпадает с round_floor p_intval 0.3–0.2–0.4–0.5совпадает с round_down number_format 0.4–0.3–0.4–0.6совпадает с round_half_up sprintf 0.4–0.3–0.4–0.6совпадает с round_half_up
Таким образом, получаем следующие различные наборы функций:
- round, number_format, sprintf используют метод round_half_up,
- ceil (p_ceil) использует метод round_ceiling,
- floor (p_floor) использует метод round_floor,
- intval (p_intval) использует метод round_down.
Следовательно, разработчикам на PHP доступно 4 из 7 рассматриваемых методов округления:
- round_floor (округление к минус бесконечности),
- round_ceiling (округление к плюс бесконечности),
- round_half_up (арифметическое округление),
- round_down (округление к нулю).
Кроме того, intval (и как следствие, p_intval) имеет сильные ограничения на размер значения аргумента — максимальное допустимое значение аргумента intval равно MAXINT (точное значение зависит от системы). По этой причине не рекомендуется использовать функцию intval для реализации округлений при решении расчетных задач.
Реализация недостающих методов округления в PHP
Как указывалось выше, для нормального использования функций floor и ceil потребовалось реализовать функции-обертки, позволяющие указывать точность округления (количество знаков после запятой).
function p_ceil($val, $d)
<
return ceil($val*pow(10,$d))/pow(10,$d);
>
function p_floor($val, $d)
<
return floor($val*pow(10,$d))/pow(10,$d);
>
Кроме того, в PHP отсутствует реализация математической функции sgn. Нам потребуется своя:
function sgn($x)
<
return $x?($x>0?1:-1):0;
>
Т еперь, имея p_ceil, p_floor и round (как реализации, соответственно, round_ceiling, round_floor и round_half_up) и собственную реализацию sgn, мы можем воспроизвести недостающие методы округления следующим образом:
function round_down($num, $d = 0)
<
// подтасовкой знака меняем направление округления
// с минус бесконечности на ноль
return sgn($num)*p_floor(abs($num), $d);
>
function round_up($num, $d = 0)
<
// подтасовкой знака меняем направление округления
// с плюс бесконечности на <от нуля>
return sgn($num)*p_ceil(abs($num), $d);
>
function round_half_down($num, $d = 0)
<
// Если последняя цифра > 5
// то округляем вверх
// иначе округляем вниз
return((2*round_up($num,$d)==round_up(2*$num,$d))
? round($num,$d)
: round_down($num,$d) );
>
function round_half_even($num, $d = 0)
<
// Если округляемая цифра !=5, то
// всё ясно, округление стандартное
if( round($num,$d) == round_half_down($num,$d) )
return round($num,$d);
// Получаем предпоследнюю цифру
$pre_digit = round_down( $num, $d );
// Если она четная
if( ($pre_digit/2) == round_down($pre_digit/2,$d) )
// то округляем вниз
return round_down($num, $d);
else
// иначе округляем вверх
return round_up($num, $d);
>
Данный код не является единственным или наилучшим способом реализации указанных методов округления, а являются лишь иллюстрацией возможности их реализации через имеющиеся стандартные функции PHP.