PHP Conference Japan 2024

round

(PHP 4, PHP 5, PHP 7, PHP 8)

round对浮点数进行四舍五入

描述

round(int|float $num, int $precision = 0, int $mode = PHP_ROUND_HALF_UP): float

返回num四舍五入到指定precision(小数点后位数)的值。precision也可以是负数或零(默认值)。

参数

num

要四舍五入的值。

precision

可选的小数位数,用于四舍五入。

如果precision为正数,则num将四舍五入到小数点后precision位有效数字。

如果precision为负数,则num将四舍五入到小数点前precision位有效数字,即四舍五入到pow(10, -$precision)的最近倍数,例如,对于precision为-1,num将四舍五入到十位数,对于precision为-2,将四舍五入到百位数,依此类推。

mode

使用以下常量之一来指定四舍五入发生的模式。

常量 描述
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() 示例

<?php
var_dump
(round(3.4));
var_dump(round(3.5));
var_dump(round(3.6));
var_dump(round(3.6, 0));
var_dump(round(5.045, 2));
var_dump(round(5.055, 2));
var_dump(round(345, -2));
var_dump(round(345, -3));
var_dump(round(678, -2));
var_dump(round(678, -3));
?>

以上示例将输出

float(3)
float(4)
float(4)
float(4)
float(5.05)
float(5.06)
float(300)
float(0)
float(700)
float(1000)

示例 #2 precision如何影响浮点数

<?php
$number
= 135.79;

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));
?>

以上示例将输出

float(135.79)
float(135.79)
float(135.8)
float(136)
float(140)
float(100)
float(0)

示例 #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));
?>

以上示例将输出

Rounding modes with 9.5
float(10)
float(9)
float(10)
float(9)

Rounding modes with 8.5
float(9)
float(8)
float(8)
float(9)

示例 #4 modeprecision 示例

<?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));
?>

以上示例将输出

Using PHP_ROUND_HALF_UP with 1 decimal digit precision
float(1.6)
float(-1.6)

Using PHP_ROUND_HALF_DOWN with 1 decimal digit precision
float(1.5)
float(-1.5)

Using PHP_ROUND_HALF_EVEN with 1 decimal digit precision
float(1.6)
float(-1.6)

Using PHP_ROUND_HALF_ODD with 1 decimal digit precision
float(1.5)
float(-1.5)

参见

添加备注

用户贡献的备注 29 条备注

takingsides at gmail dot com
10 年前
在我看来,此函数缺少两个标志

- PHP_ROUND_UP - 始终向上舍入。
- PHP_ROUND_DOWN - 始终向下舍入。

在会计中,通常需要始终向上或向下舍入到千分之一的精度。

<?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);
}
?>
depaula at unilogica dot com
7 年前
由于 PHP 没有原生的数字截断函数,所以这是我的解决方案——如果您需要截断而不是四舍五入数字,则可以使用此函数。

<?php
/**
* 截断浮点数,例如: <code>truncate(-1.49999, 2); // 返回 -1.49
* truncate(.49999, 3); // 返回 0.499
* </code>
* @param float $val 要截断的浮点数
* @param int f 精度
* @return float
*/
function truncate($val, $f="0")
{
if((
$p = strpos($val, '.')) !== false) {
$val = floatval(substr($val, 0, $p + 1 + $f));
}
return
$val;
}
?>

最初发布在 http://stackoverflow.com/a/12710283/1596489
slimusgm at gmail dot com
10 年前
如果您有负零并且需要返回正数,只需添加 +0

$number = -2.38419e-07;
var_dump(round($number,1));//float(-0)
var_dump(round($number,1) + 0);//float(0)
Mojo urk
6 年前
解决 round_down() 问题
-----------------------------
使用 <?php floor(pow(10, $precision) * $value) / pow(10, $precision); ?> 在某些情况下会失败,例如 round_down(2.05, 2) 会给出错误的结果 2.04。
这是一个针对此问题的“字符串”解决方案(https://stackoverflow.com/a/26491492/1245149)(未涵盖负精度)

<?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));
}
?>

解决 round_up() 问题
---------------------------
使用 <?php ceil(pow(10, $precision) * $value) / pow(10, $precision);?> 在某些情况下会失败,例如 round_up(2.22, 2) 会错误地返回 2.23 (https://stackoverflow.com/a/8239620/1245149).
根据上面的 round_down() “字符串”解决方案,我得到了以下结果(未涵盖负精度)

<?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); // 这是否总是给出正确的结果?
}
else {
$ceilValue = $floorValue;
}
return
$ceilValue;
}
?>

我不知道它是否万无一失,但至少它消除了上述失败。我没有进行二进制到十进制数学分析,但是如果 `$floorValue + pow(10, 0 - $precision)` 总是按预期工作
那么它应该没问题。
serg at kalachev dot ru
10 年前
类似 Excel 的 ROUNDUP 函数

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
jongbumi at gmail dot com
8 年前
PHP 5.3, 5.4, 5.5
<?php
$fInfinty
= pow(1000, 1000); // float(INF)
$fResult = round(123.456, $fInfinty); // double(123)
?>

PHP 5.6
<?php
$fInfinty
= pow(1000, 1000); // float(INF)
$fResult = round(123.456, $fInfinty); // float(0)
?>

PHP 7
<?php
$fInfinty
= pow(1000, 1000); // float(INF)
$fResult = round(123.456, $fInfinty); // null
?>
djcox99 at googlemail dot com
10 年前
我发现,在某些情况下,将数字转换为字符串后,使用 round 进行舍入可能会出现舍入误差。

为了解决这个问题,我将 round() 替换为 number_format()。

不幸的是,我无法提供示例(因为该数字无法表示为字符串!)

基本上,我有 round(0.688888889,2);

当打印为字符串时,它将保持为 0.68888889。

但是使用 number_format,它正确地变成了 0.69。
esion99 at gmail dot com
10 年前
意外结果或误解 (php v5.5.9)

<?php

echo round(1.55, 1, PHP_ROUND_HALF_DOWN); // 1.5
echo round(1.551, 1, PHP_ROUND_HALF_DOWN); //1.6

?>
christian at deligant dot net
13 年前
此函数(以及所有数学运算符)会处理 `setlocale` 设置,当在预期使用英语数学表示法的上下文中使用结果时,会导致一些奇怪的结果,例如在 `width:` 样式属性中的结果打印!

<?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
?>
twan at ecreation dot nl
24 年前
如果您只想对显示变量进行舍入(而不是对舍入结果进行计算),则应使用带浮点数的 printf

<?php printf ("%6.2f",3.39532); ?>

这将返回:3.40。
craft at ckdevelop dot org
10 年前
function mround($val, $f=2, $d=6){
return sprintf("%".$d.".".$f."f", $val);
}

echo mround(34.89999); //34.90
匿名用户
14 年前
这是一个舍入到指定增量的函数,但总是向上舍入。我必须将它用于价格调整,价格总是向上舍入到 5 美元的增量。

<?php
function roundUpTo($number, $increments) {
$increments = 1 / $increments;
return (
ceil($number * $increments) / $increments);
}
?>
michaeldnelson dot mdn at gmail dot com
15 年前
此函数允许您舍入到任意非零数字。当然,零会导致除以零错误。

<?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
?>
greghenle at gmail dot com
8 年前
/**
* 四舍五入到首位有效数字
* +N 到 +无穷大
* -N 到 -无穷大
*
*/
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;

/**
* 输出结果
*
* 40000000
* 200000
* 0.08
* 0
* -0.08
*
*/
dastra
12年前
当舍入的浮点数足够小时,round() 有时会返回 E 表示法 - 请参见 https://bugs.php.net/bug.php?id=44223。这显然是一个特性。

在转换为字符串时,为了解决此“特性”,请将 round 语句用 sprintf 包裹起来

sprintf("%.10f", round( $amountToBeRounded, 10));
php at silisoftware dot com
22年前
这是一个舍入到任意数量有效数字的函数。不要将其与舍入到负精度混淆 - 负精度是从小数点向后计数,此函数是从最高有效数字向前计数。

例如

<?php
round
(1241757, -3); // 1242000
RoundSigDigs(1241757, 3); // 1240000
?>

也适用于负数。$sigdigs 应 >= 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;
}
?>
martinr at maarja dot net
16年前
请注意,此函数输出的格式也取决于您的区域设置。例如,如果您将区域设置设置为使用逗号分隔小数位的国家/地区,则此函数的输出也使用逗号而不是点。

当您将舍入后的浮点数输入到需要用点分隔小数位的数据库中时,这可能会成为问题。

实际操作
<?php
echo round('3.5558', 2);
setlocale(constant('LC_ALL'), 'et_EE.UTF-8');
echo
'<br />'. round('3.5558', 2);
?>

输出结果将是
3.56
3,56
Anonymous
8 年前
请注意,PHP 5.3 不仅仅引入了 $mode,它还完全重写了舍入实现,以消除浮点值舍入中常见的许多错误。

这就是为什么即使 floor/ceil 没有给出正确结果,round() 也会给出正确结果的原因。
例如,floor(0.285 * 100 + 0.5) VS round(0.285*100 + 0.5)。前者给出 28,后者给出 29。

更多详细信息请参见:https://wiki.php.net/rfc/rounding
feha at vision dot to
14 年前
这是一个简短而简洁的函数,用于舍入分钟(小时)……

<?php

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);
}

?>

您决定舍入到最接近的分钟……
示例将产生:14:05
goreyshi at gmail dot com
6 年前
当您处理美元等货币时,您需要在以下条件下显示它
-所有数字都用两位小数表示美分。
-用逗号分隔千位数。
-对于超过两位小数的数字,向下舍入。

我使用 number_format 函数内的 round 函数来实现它

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
omnibus at omnibus dot edu dot pl
14 年前
如果数字为负数且精度大于逗号后实际数字位的数量,请注意其奇怪的行为。

round(-0.07, 4);

返回

-0.07000000000000001

因此,如果您根据需要逗号后最大位数的正则表达式对其进行验证,则会遇到麻烦。
Astro
4年前
好的,我的函数的最终版本

function NumberPrecision($n, $precision=0, $is_round=true)
{
if ($is_round)
{
$r = 5 * pow(10, -($precision+1));
$n += (($n < 0) ? -$r : $r);
}

$comma = '.';

$r = 5 * pow(10, -($precision+2));
$n += (($n > 0) ? -$r : $r);
$n = number_format($n, $precision+1, $comma, '');

$n .= $comma;
list($n, $frac) = explode($comma, $n, 2);
$n = rtrim(rtrim($n, $comma) . $comma . substr($frac, 0, $precision), $comma);
return ($n);
}

当内置函数如 round() 或 number_format() 返回意外结果时,它在某些情况下可能很有用。适用于正数、负数、零、如 1/12、0.3 的数字、科学计数法中的数字等。
terry at scribendi dot com
20年前
要将任何数字舍入到给定数量的有效数字,请使用 log10 来找出它的数量级

<?php round($n, ceil(0 - log10($n)) + $sigdigits); ?>

或者,当您必须显示每单位价格(可能少于几美分/便士/日元)时,您可以使用

<?php
// $exp = 货币小数位数 - 日元/韩元为 0,大多数其他货币为 2
$dp = ceil(0 - log10($n)) + $sigdigits;
$display = number_format($amount, ($exp>$dp)?$exp:$dp);
?>

这始终显示货币所需的至少小数位数,但如果显示具有精度的单价需要更多小数位数,则会显示更多小数位数 - 例如:“英语校对,每字 $0.0068”,“英国啤酒,每品脱 $6.80”。
Anonymous
15 年前
此函数如果双精度或浮点值大于“$nb.5”,则返回 ceil($nb),否则返回 floor($nb)

<?php
function arounds_int($nb) {

if(!
is_numeric($nb)) {
return
false;
}

$sup = round($nb);
$inf = floor($nb);
$try = (double) $inf . '.5' ;

if(
$nb > $try) {
return
$sup;
}

return
$inf;
}
?>
匿名用户
7 年前
此函数行为异常。

<?php
echo round(0.045, 2); // 0.05
echo round(0.45, 1); // 0.5
echo round(1.045-1, 2); // 0.04 !!!
echo round(1.45-1, 1); // 0.5
Hayley Watson
5年前
需要指出的是,此页面中所谓的“精度”更准确地应称为“准确度”;精度是指小数点两侧有效数字的总数,而准确度是指小数点右侧的数字位数。这是一个常见的误解。
spectrumcat at gmail dot com
10 年前
如果有人需要“优雅”的舍入(更改其精度以获得非零值),这里有一个简单的函数

function gracefulRound($val, $min = 2, $max = 4) {
$result = round($val, $min);
if ($result == 0 && $min < $max) {
return gracefulRound($val, ++$min, $max);
} else {
return $result;
}
}

用法
$_ = array(0.5, 0.023, 0.008, 0.0007, 0.000079, 0.0000048);
foreach ($_ as $val) {
echo "{$val}: ".gracefulRound($val)."\n";
}

输出
0.5: 0.5
0.023: 0.02
0.008: 0.01
0.0007: 0.001
0.000079: 0.0001
0.0000048: 0
maxteiber at gmail dot com
18年前
此函数的结果始终取决于底层的 C 函数。此函数存在许多编译器错误和浮点精度问题。目前,以下代码

<?php
echo round(141.075, 2);
?>

返回

141.07

在我的机器上。
因此,在执行会计等关键计算时,切勿真正信任此函数!
替代方案:仅使用整数或使用字符串比较。
php at persignum dot com
9年前
由于此函数缺少向上舍入和向下舍入常量,并且上面的说明并未真正显示如何向上或向下舍入到最接近的数字,因此这里介绍一种始终向上或始终向下舍入到最接近数字的简单方法。

int 是您要舍入的数字

n 是您要舍入到的最接近的数字。

向上舍入到最接近的数字

function round_up($int, $n) {
return ceil($int / $n) * $n;
}

向下舍入到最接近的数字

function round_down(int, $n) {
return floor($int / $n) * $n;
}
To Top