[RFC] Add bcfloor, bcceil and bcround to BCMath (#13096)

Implementation for the "Adding bcround, bcfloor and bcceil to BCMath" RFC: https://wiki.php.net/rfc/adding_bcround_bcfloor_bcceil_to_bcmath

* Separated round mode into separate header file

Co-authored-by: Gina Peter Banyard <girgias@php.net>
This commit is contained in:
Saki Takamachi 2024-05-01 02:32:33 +09:00 committed by GitHub
parent 78ec2bde62
commit 5359392717
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
27 changed files with 1500 additions and 38 deletions

View file

@ -27,6 +27,9 @@ static const func_info_t func_infos[] = {
F1("bcpowmod", MAY_BE_STRING),
F1("bcpow", MAY_BE_STRING),
F1("bcsqrt", MAY_BE_STRING),
F1("bcfloor", MAY_BE_STRING),
F1("bcceil", MAY_BE_STRING),
F1("bcround", MAY_BE_STRING),
FN("bzopen", MAY_BE_RESOURCE|MAY_BE_FALSE),
F1("bzerror", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_LONG|MAY_BE_ARRAY_OF_STRING),
F1("cal_from_jd", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_LONG|MAY_BE_ARRAY_OF_STRING|MAY_BE_ARRAY_OF_NULL),

View file

@ -643,6 +643,96 @@ PHP_FUNCTION(bccomp)
}
/* }}} */
/* {{{ floor or ceil */
static void bcfloor_or_bcceil(INTERNAL_FUNCTION_PARAMETERS, bool is_floor)
{
zend_string *numstr;
bc_num num, result;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_STR(numstr)
ZEND_PARSE_PARAMETERS_END();
bc_init_num(&num);
bc_init_num(&result);
if (php_str2num(&num, ZSTR_VAL(numstr)) == FAILURE) {
zend_argument_value_error(1, "is not well-formed");
goto cleanup;
}
bc_floor_or_ceil(num, is_floor, &result);
RETVAL_STR(bc_num2str_ex(result, 0));
cleanup: {
bc_free_num(&num);
bc_free_num(&result);
};
}
/* }}} */
/* {{{ Returns floor of num */
PHP_FUNCTION(bcfloor)
{
bcfloor_or_bcceil(INTERNAL_FUNCTION_PARAM_PASSTHRU, true);
}
/* }}} */
/* {{{ Returns ceil of num */
PHP_FUNCTION(bcceil)
{
bcfloor_or_bcceil(INTERNAL_FUNCTION_PARAM_PASSTHRU, false);
}
/* }}} */
/* {{{ Returns num rounded to the digits specified by precision. */
PHP_FUNCTION(bcround)
{
zend_string *numstr;
zend_long precision = 0;
zend_long mode = PHP_ROUND_HALF_UP;
bc_num num, result;
ZEND_PARSE_PARAMETERS_START(1, 3)
Z_PARAM_STR(numstr)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(precision)
Z_PARAM_LONG(mode)
ZEND_PARSE_PARAMETERS_END();
switch (mode) {
case PHP_ROUND_HALF_UP:
case PHP_ROUND_HALF_DOWN:
case PHP_ROUND_HALF_EVEN:
case PHP_ROUND_HALF_ODD:
case PHP_ROUND_CEILING:
case PHP_ROUND_FLOOR:
case PHP_ROUND_TOWARD_ZERO:
case PHP_ROUND_AWAY_FROM_ZERO:
break;
default:
zend_argument_value_error(3, "must be a valid rounding mode (PHP_ROUND_*)");
return;
}
bc_init_num(&num);
bc_init_num(&result);
if (php_str2num(&num, ZSTR_VAL(numstr)) == FAILURE) {
zend_argument_value_error(1, "is not well-formed");
goto cleanup;
}
bc_round(num, precision, mode, &result);
RETVAL_STR(bc_num2str_ex(result, result->n_scale));
cleanup: {
bc_free_num(&num);
bc_free_num(&result);
};
}
/* }}} */
/* {{{ Sets default scale parameter for all bc math functions */
PHP_FUNCTION(bcscale)
{

View file

@ -29,3 +29,12 @@ function bcsqrt(string $num, ?int $scale = null): string {}
function bccomp(string $num1, string $num2, ?int $scale = null): int {}
function bcscale(?int $scale = null): int {}
/** @refcount 1 */
function bcfloor(string $num): string {}
/** @refcount 1 */
function bcceil(string $num): string {}
/** @refcount 1 */
function bcround(string $num, int $precision = 0, int $mode = PHP_ROUND_HALF_UP): string {}

View file

@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: f28dafc2a279f5421cd0d0e668fde0032e996ebc */
* Stub hash: cd3d182e13cb0ca22b27c13a8d0a86c20fde5b76 */
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_bcadd, 0, 2, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, num1, IS_STRING, 0)
@ -43,6 +43,18 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_bcscale, 0, 0, IS_LONG, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, scale, IS_LONG, 1, "null")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_bcfloor, 0, 1, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, num, IS_STRING, 0)
ZEND_END_ARG_INFO()
#define arginfo_bcceil arginfo_bcfloor
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_bcround, 0, 1, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, num, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, precision, IS_LONG, 0, "0")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, mode, IS_LONG, 0, "PHP_ROUND_HALF_UP")
ZEND_END_ARG_INFO()
ZEND_FUNCTION(bcadd);
ZEND_FUNCTION(bcsub);
ZEND_FUNCTION(bcmul);
@ -53,6 +65,9 @@ ZEND_FUNCTION(bcpow);
ZEND_FUNCTION(bcsqrt);
ZEND_FUNCTION(bccomp);
ZEND_FUNCTION(bcscale);
ZEND_FUNCTION(bcfloor);
ZEND_FUNCTION(bcceil);
ZEND_FUNCTION(bcround);
static const zend_function_entry ext_functions[] = {
ZEND_FE(bcadd, arginfo_bcadd)
@ -65,5 +80,8 @@ static const zend_function_entry ext_functions[] = {
ZEND_FE(bcsqrt, arginfo_bcsqrt)
ZEND_FE(bccomp, arginfo_bccomp)
ZEND_FE(bcscale, arginfo_bcscale)
ZEND_FE(bcfloor, arginfo_bcfloor)
ZEND_FE(bcceil, arginfo_bcceil)
ZEND_FE(bcround, arginfo_bcround)
ZEND_FE_END
};

View file

@ -7,8 +7,8 @@ if test "$PHP_BCMATH" != "no"; then
PHP_NEW_EXTENSION(bcmath, bcmath.c \
libbcmath/src/add.c libbcmath/src/div.c libbcmath/src/init.c libbcmath/src/neg.c libbcmath/src/raisemod.c libbcmath/src/sub.c \
libbcmath/src/compare.c libbcmath/src/divmod.c libbcmath/src/int2num.c libbcmath/src/num2long.c libbcmath/src/output.c libbcmath/src/recmul.c \
libbcmath/src/sqrt.c libbcmath/src/zero.c libbcmath/src/doaddsub.c libbcmath/src/nearzero.c libbcmath/src/num2str.c libbcmath/src/raise.c \
libbcmath/src/rmzero.c libbcmath/src/str2num.c,
libbcmath/src/sqrt.c libbcmath/src/zero.c libbcmath/src/doaddsub.c libbcmath/src/floor_or_ceil.c libbcmath/src/nearzero.c libbcmath/src/num2str.c \
libbcmath/src/raise.c libbcmath/src/rmzero.c libbcmath/src/round.c libbcmath/src/str2num.c,
$ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1)
PHP_ADD_BUILD_DIR($ext_builddir/libbcmath/src)
AC_DEFINE(HAVE_BCMATH, 1, [Whether you have bcmath])

View file

@ -7,7 +7,8 @@ if (PHP_BCMATH == "yes") {
ADD_SOURCES("ext/bcmath/libbcmath/src", "add.c div.c init.c neg.c \
raisemod.c sub.c compare.c divmod.c int2num.c \
num2long.c output.c recmul.c sqrt.c zero.c doaddsub.c \
nearzero.c num2str.c raise.c rmzero.c str2num.c", "bcmath");
floor_or_ceil.c nearzero.c num2str.c raise.c rmzero.c str2num.c \
round.c", "bcmath");
AC_DEFINE('HAVE_BCMATH', 1, 'Have BCMATH library');
}

View file

@ -58,7 +58,9 @@ typedef struct bc_struct {
#include "zend.h"
#include <stdbool.h>
#include "zend_string.h"
#include "../../php_bcmath.h" /* Needed for BCG() macro */
/* Needed for BCG() macro and PHP_ROUND_XXX */
#include "../../php_bcmath.h"
/* The base used in storing the numbers in n_value above.
Currently, this MUST be 10. */
@ -125,6 +127,10 @@ bool bc_modulo(bc_num num1, bc_num num2, bc_num *resul, size_t scale);
bool bc_divmod(bc_num num1, bc_num num2, bc_num *quo, bc_num *rem, size_t scale);
void bc_floor_or_ceil(bc_num num, bool is_floor, bc_num *result);
void bc_round(bc_num num, zend_long places, zend_long mode, bc_num *result);
typedef enum {
OK,
BASE_HAS_FRACTIONAL,

View file

@ -0,0 +1,57 @@
/*
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Saki Takamachi <saki@php.net> |
+----------------------------------------------------------------------+
*/
#include "bcmath.h"
#include "private.h"
#include <stddef.h>
void bc_floor_or_ceil(bc_num num, bool is_floor, bc_num *result)
{
/* clear result */
bc_free_num(result);
/* Initialize result */
*result = bc_new_num(num->n_len, 0);
(*result)->n_sign = num->n_sign;
/* copy integer part */
memcpy((*result)->n_value, num->n_value, num->n_len);
/* If the number is positive and we are flooring, then nothing else needs to be done.
* Similarly, if the number is negative and we are ceiling, then nothing else needs to be done. */
if (num->n_scale == 0 || (*result)->n_sign == (is_floor ? PLUS : MINUS)) {
return;
}
/* check fractional part. */
size_t count = num->n_scale;
const char *nptr = num->n_value + num->n_len;
while ((count > 0) && (*nptr == 0)) {
count--;
nptr++;
}
/* If all digits past the decimal point are 0 */
if (count == 0) {
return;
}
/* Increment the absolute value of the result by 1 and add sign information */
bc_num tmp = _bc_do_add(*result, BCG(_one_), 0);
tmp->n_sign = (*result)->n_sign;
bc_free_num(result);
*result = tmp;
}

View file

@ -0,0 +1,179 @@
/*
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Saki Takamachi <saki@php.net> |
+----------------------------------------------------------------------+
*/
#include "bcmath.h"
#include "private.h"
#include <stddef.h>
void bc_round(bc_num num, zend_long precision, zend_long mode, bc_num *result)
{
/* clear result */
bc_free_num(result);
/*
* The following cases result in an early return:
*
* - When rounding to an integer part which is larger than the number
* e.g. Rounding 21.123 to 3 digits before the decimal point.
* - When rounding to a greater decimal precision then the number has, the number is unchanged
* e.g. Rounding 21.123 to 4 digits after the decimal point.
* - If the fractional part ends with zeros, the zeros are omitted and the number of digits in num is reduced.
* Meaning we might end up in the previous case.
*/
if (precision < 0 && num->n_len < (size_t) (-(precision + Z_L(1))) + 1) {
*result = bc_copy_num(BCG(_zero_));
return;
}
/* Just like bcadd('1', '1', 4) becomes '2.0000', it pads with zeros at the end if necessary. */
if (precision >= 0 && num->n_scale <= precision) {
if (num->n_scale == precision) {
*result = bc_copy_num(num);
} else if(num->n_scale < precision) {
*result = bc_new_num(num->n_len, precision);
(*result)->n_sign = num->n_sign;
memcpy((*result)->n_value, num->n_value, num->n_len + num->n_scale);
}
return;
}
/*
* If the calculation result is a negative value, there is an early return,
* so no underflow will occur.
*/
size_t rounded_len = num->n_len + precision;
/*
* Initialize result
* For example, if rounded_len is 0, it means trying to round 50 to 100 or 0.
* If the result of rounding is carried over, it will be added later, so first set it to 0 here.
*/
if (rounded_len == 0) {
*result = bc_copy_num(BCG(_zero_));
} else {
*result = bc_new_num(num->n_len, precision > 0 ? precision : 0);
memcpy((*result)->n_value, num->n_value, rounded_len);
}
(*result)->n_sign = num->n_sign;
const char *nptr = num->n_value + rounded_len;
/* Check cases that can be determined without looping. */
switch (mode) {
case PHP_ROUND_HALF_UP:
if (*nptr >= 5) {
goto up;
} else if (*nptr < 5) {
return;
}
break;
case PHP_ROUND_HALF_DOWN:
case PHP_ROUND_HALF_EVEN:
case PHP_ROUND_HALF_ODD:
if (*nptr > 5) {
goto up;
} else if (*nptr < 5) {
return;
}
/* if *nptr == 5, we need to look-up further digits before making a decision. */
break;
case PHP_ROUND_CEILING:
if (num->n_sign != PLUS) {
return;
} else if (*nptr > 0) {
goto up;
}
/* if *nptr == 0, a loop is required for judgment. */
break;
case PHP_ROUND_FLOOR:
if (num->n_sign != MINUS) {
return;
} else if (*nptr > 0) {
goto up;
}
/* if *nptr == 0, a loop is required for judgment. */
break;
case PHP_ROUND_TOWARD_ZERO:
return;
case PHP_ROUND_AWAY_FROM_ZERO:
if (*nptr > 0) {
goto up;
}
/* if *nptr == 0, a loop is required for judgment. */
break;
EMPTY_SWITCH_DEFAULT_CASE()
}
/* Loop through the remaining digits. */
size_t count = num->n_len + num->n_scale - rounded_len - 1;
nptr++;
while ((count > 0) && (*nptr == 0)) {
count--;
nptr++;
}
if (count > 0) {
goto up;
}
switch (mode) {
case PHP_ROUND_HALF_DOWN:
case PHP_ROUND_CEILING:
case PHP_ROUND_FLOOR:
case PHP_ROUND_AWAY_FROM_ZERO:
return;
case PHP_ROUND_HALF_EVEN:
if (rounded_len == 0 || num->n_value[rounded_len - 1] % 2 == 0) {
return;
}
break;
case PHP_ROUND_HALF_ODD:
if (rounded_len != 0 && num->n_value[rounded_len - 1] % 2 == 1) {
return;
}
break;
EMPTY_SWITCH_DEFAULT_CASE()
}
up:
{
bc_num tmp;
if (rounded_len == 0) {
tmp = bc_new_num(num->n_len + 1, 0);
tmp->n_value[0] = 1;
tmp->n_sign = num->n_sign;
} else {
bc_num scaled_one = bc_new_num((*result)->n_len, (*result)->n_scale);
scaled_one->n_value[rounded_len - 1] = 1;
tmp = _bc_do_add(*result, scaled_one, (*result)->n_scale);
tmp->n_sign = (*result)->n_sign;
bc_free_num(&scaled_one);
}
bc_free_num(result);
*result = tmp;
}
}

View file

@ -19,6 +19,7 @@
#include "libbcmath/src/bcmath.h"
#include "zend_API.h"
#include "ext/standard/php_math_round_mode.h"
extern zend_module_entry bcmath_module_entry;
#define phpext_bcmath_ptr &bcmath_module_entry

View file

@ -0,0 +1,46 @@
--TEST--
bcceil() function
--EXTENSIONS--
bcmath
--FILE--
<?php
$nums = [
'0',
'0.00',
'-0',
'-0.00',
'0.01',
'0.000000000000000000000000000000000000000001',
'-0.01',
'-0.000000000000000000000000000000000000000001',
'1',
'1.0000',
'1.0001',
'100000.000000000000000000000000000000000000000001',
'-1',
'-1.0000',
'-1.0001',
'-100000.000000000000000000000000000000000000000001',
];
foreach ($nums as $num) {
echo str_pad("$num", 50, ' ', STR_PAD_LEFT), ' => ', bcceil($num), "\n";
}
?>
--EXPECT--
0 => 0
0.00 => 0
-0 => 0
-0.00 => 0
0.01 => 1
0.000000000000000000000000000000000000000001 => 1
-0.01 => 0
-0.000000000000000000000000000000000000000001 => 0
1 => 1
1.0000 => 1
1.0001 => 2
100000.000000000000000000000000000000000000000001 => 100001
-1 => -1
-1.0000 => -1
-1.0001 => -1
-100000.000000000000000000000000000000000000000001 => -100000

View file

@ -0,0 +1,21 @@
--TEST--
bcceil() function with error
--EXTENSIONS--
bcmath
--FILE--
<?php
try {
bcceil('hoge');
} catch (Throwable $e) {
echo $e->getMessage()."\n";
}
try {
bcceil('0.00.1');
} catch (Throwable $e) {
echo $e->getMessage()."\n";
}
?>
--EXPECT--
bcceil(): Argument #1 ($num) is not well-formed
bcceil(): Argument #1 ($num) is not well-formed

View file

@ -0,0 +1,46 @@
--TEST--
bcfloor() function
--EXTENSIONS--
bcmath
--FILE--
<?php
$nums = [
'0',
'0.00',
'-0',
'-0.00',
'0.01',
'0.000000000000000000000000000000000000000001',
'-0.01',
'-0.000000000000000000000000000000000000000001',
'1',
'1.0000',
'1.0001',
'100000.000000000000000000000000000000000000000001',
'-1',
'-1.0000',
'-1.0001',
'-100000.000000000000000000000000000000000000000001',
];
foreach ($nums as $num) {
echo str_pad("$num", 50, ' ', STR_PAD_LEFT), ' => ', bcfloor($num), "\n";
}
?>
--EXPECT--
0 => 0
0.00 => 0
-0 => 0
-0.00 => 0
0.01 => 0
0.000000000000000000000000000000000000000001 => 0
-0.01 => -1
-0.000000000000000000000000000000000000000001 => -1
1 => 1
1.0000 => 1
1.0001 => 1
100000.000000000000000000000000000000000000000001 => 100000
-1 => -1
-1.0000 => -1
-1.0001 => -2
-100000.000000000000000000000000000000000000000001 => -100001

View file

@ -0,0 +1,21 @@
--TEST--
bcfloor() function with error
--EXTENSIONS--
bcmath
--FILE--
<?php
try {
bcfloor('hoge');
} catch (Throwable $e) {
echo $e->getMessage()."\n";
}
try {
bcfloor('0.00.1');
} catch (Throwable $e) {
echo $e->getMessage()."\n";
}
?>
--EXPECT--
bcfloor(): Argument #1 ($num) is not well-formed
bcfloor(): Argument #1 ($num) is not well-formed

View file

@ -0,0 +1,89 @@
--TEST--
bcround() function PHP_ROUND_AWAY_FROM_ZERO
--EXTENSIONS--
bcmath
--FILE--
<?php
require_once __DIR__ . '/bcround_test_helper.inc';
run_round_test(PHP_ROUND_AWAY_FROM_ZERO);
?>
--EXPECT--
========== non-boundary value ==========
[1.1, 0] => 2
[1.2, 0] => 2
[1.3, 0] => 2
[1.4, 0] => 2
[1.6, 0] => 2
[1.7, 0] => 2
[1.8, 0] => 2
[1.9, 0] => 2
[-1.1, 0] => -2
[-1.2, 0] => -2
[-1.3, 0] => -2
[-1.4, 0] => -2
[-1.6, 0] => -2
[-1.7, 0] => -2
[-1.8, 0] => -2
[-1.9, 0] => -2
========== minus precision ==========
[50, -2] => 100
[-50, -2] => -100
[1230, -1] => 1230
[1235, -1] => 1240
[-1230, -1] => -1230
[-1235, -1] => -1240
[3400.0000, -2] => 3400
[3400.0001, -2] => 3500
[3450.0000, -2] => 3500
[3450.0001, -2] => 3500
[-3400.0000, -2] => -3400
[-3400.0001, -2] => -3500
[-3450.0000, -2] => -3500
[-3450.0001, -2] => -3500
========== zero precision ==========
[1235, 0] => 1235
[1235.0, 0] => 1235
[1235.000001, 0] => 1236
[1235.5, 0] => 1236
[1235.500001, 0] => 1236
[-1235, 0] => -1235
[-1235.0, 0] => -1235
[-1235.000001, 0] => -1236
[-1235.5, 0] => -1236
[-1235.500001, 0] => -1236
[0.0001, 0] => 1
[0.5, 0] => 1
[0.5000, 0] => 1
[0.5001, 0] => 1
[-0.0001, 0] => -1
[-0.5, 0] => -1
[-0.5000, 0] => -1
[-0.5001, 0] => -1
========== plus precision ==========
[28.40, 1] => 28.4
[28.4000001, 1] => 28.5
[28.45, 1] => 28.5
[28.4500001, 1] => 28.5
[-28.40, 1] => -28.4
[-28.4000001, 1] => -28.5
[-28.45, 1] => -28.5
[-28.4500001, 1] => -28.5
[153.90, 1] => 153.9
[153.9000001, 1] => 154.0
[153.95, 1] => 154.0
[153.9500001, 1] => 154.0
[-153.90, 1] => -153.9
[-153.9000001, 1] => -154.0
[-153.95, 1] => -154.0
[-153.9500001, 1] => -154.0
[0.000001, 3] => 0.001
[0.0005, 3] => 0.001
[0.000500, 3] => 0.001
[0.000501, 3] => 0.001
[-0.000001, 3] => -0.001
[-0.0005, 3] => -0.001
[-0.000500, 3] => -0.001
[-0.000501, 3] => -0.001

View file

@ -0,0 +1,89 @@
--TEST--
bcround() function PHP_ROUND_CEILING
--EXTENSIONS--
bcmath
--FILE--
<?php
require_once __DIR__ . '/bcround_test_helper.inc';
run_round_test(PHP_ROUND_CEILING);
?>
--EXPECT--
========== non-boundary value ==========
[1.1, 0] => 2
[1.2, 0] => 2
[1.3, 0] => 2
[1.4, 0] => 2
[1.6, 0] => 2
[1.7, 0] => 2
[1.8, 0] => 2
[1.9, 0] => 2
[-1.1, 0] => -1
[-1.2, 0] => -1
[-1.3, 0] => -1
[-1.4, 0] => -1
[-1.6, 0] => -1
[-1.7, 0] => -1
[-1.8, 0] => -1
[-1.9, 0] => -1
========== minus precision ==========
[50, -2] => 100
[-50, -2] => 0
[1230, -1] => 1230
[1235, -1] => 1240
[-1230, -1] => -1230
[-1235, -1] => -1230
[3400.0000, -2] => 3400
[3400.0001, -2] => 3500
[3450.0000, -2] => 3500
[3450.0001, -2] => 3500
[-3400.0000, -2] => -3400
[-3400.0001, -2] => -3400
[-3450.0000, -2] => -3400
[-3450.0001, -2] => -3400
========== zero precision ==========
[1235, 0] => 1235
[1235.0, 0] => 1235
[1235.000001, 0] => 1236
[1235.5, 0] => 1236
[1235.500001, 0] => 1236
[-1235, 0] => -1235
[-1235.0, 0] => -1235
[-1235.000001, 0] => -1235
[-1235.5, 0] => -1235
[-1235.500001, 0] => -1235
[0.0001, 0] => 1
[0.5, 0] => 1
[0.5000, 0] => 1
[0.5001, 0] => 1
[-0.0001, 0] => 0
[-0.5, 0] => 0
[-0.5000, 0] => 0
[-0.5001, 0] => 0
========== plus precision ==========
[28.40, 1] => 28.4
[28.4000001, 1] => 28.5
[28.45, 1] => 28.5
[28.4500001, 1] => 28.5
[-28.40, 1] => -28.4
[-28.4000001, 1] => -28.4
[-28.45, 1] => -28.4
[-28.4500001, 1] => -28.4
[153.90, 1] => 153.9
[153.9000001, 1] => 154.0
[153.95, 1] => 154.0
[153.9500001, 1] => 154.0
[-153.90, 1] => -153.9
[-153.9000001, 1] => -153.9
[-153.95, 1] => -153.9
[-153.9500001, 1] => -153.9
[0.000001, 3] => 0.001
[0.0005, 3] => 0.001
[0.000500, 3] => 0.001
[0.000501, 3] => 0.001
[-0.000001, 3] => 0.000
[-0.0005, 3] => 0.000
[-0.000500, 3] => 0.000
[-0.000501, 3] => 0.000

View file

@ -0,0 +1,99 @@
--TEST--
bcround() function with early return
--EXTENSIONS--
bcmath
--FILE--
<?php
$otherModes = [
'PHP_ROUND_HALF_DOWN',
'PHP_ROUND_HALF_EVEN',
'PHP_ROUND_HALF_ODD',
'PHP_ROUND_FLOOR',
'PHP_ROUND_CEILING',
'PHP_ROUND_AWAY_FROM_ZERO',
'PHP_ROUND_TOWARD_ZERO',
];
$early_return_cases = [
['123', -4],
['123.123456', -4],
['123', 1],
['123.5', 1],
['123.5', 2],
['123.0000000000000000000001', 22],
['123.0000000000000000000001', 23],
['-123', -4],
['-123.123456', -4],
['-123', 1],
['-123.5', 1],
['-123.5', 2],
['-123.0000000000000000000001', 22],
['-123.0000000000000000000001', 23],
['0', 0],
['0.0', 0],
['0.0000', 0],
['-0', 0],
['-0.0', 0],
['-0.0000', 0],
];
$results = [
'PHP_ROUND_HALF_UP' => [],
'PHP_ROUND_HALF_DOWN' => [],
'PHP_ROUND_HALF_EVEN' => [],
'PHP_ROUND_HALF_ODD' => [],
'PHP_ROUND_FLOOR' => [],
'PHP_ROUND_CEIL' => [],
'PHP_ROUND_AWAY_FROM_ZERO' => [],
'PHP_ROUND_TOWARD_ZERO' => [],
];
foreach ($early_return_cases as [$num, $precision]) {
$result = str_pad("[{$num}, {$precision}]", 33, ' ', STR_PAD_LEFT) . ' => ' . bcround($num, $precision, PHP_ROUND_HALF_UP) . "\n";
echo $result;
$results['PHP_ROUND_HALF_UP'][] = $result;
}
echo "\n";
foreach ($otherModes as $mode) {
foreach ($early_return_cases as [$num, $precision]) {
$result = str_pad("[{$num}, {$precision}]", 33, ' ', STR_PAD_LEFT) . ' => ' . bcround($num, $precision, constant($mode)) . "\n";
$results[$mode][] = $result;
}
if ($results['PHP_ROUND_HALF_UP'] === $results[$mode]) {
echo str_pad($mode, 24, ' ', STR_PAD_LEFT) . ": result is same to PHP_ROUND_HALF_UP\n";
} else {
echo str_pad($mode, 24, ' ', STR_PAD_LEFT) . ": result is not same to PHP_ROUND_HALF_UP, failed\n";
}
}
?>
--EXPECT--
[123, -4] => 0
[123.123456, -4] => 0
[123, 1] => 123.0
[123.5, 1] => 123.5
[123.5, 2] => 123.50
[123.0000000000000000000001, 22] => 123.0000000000000000000001
[123.0000000000000000000001, 23] => 123.00000000000000000000010
[-123, -4] => 0
[-123.123456, -4] => 0
[-123, 1] => -123.0
[-123.5, 1] => -123.5
[-123.5, 2] => -123.50
[-123.0000000000000000000001, 22] => -123.0000000000000000000001
[-123.0000000000000000000001, 23] => -123.00000000000000000000010
[0, 0] => 0
[0.0, 0] => 0
[0.0000, 0] => 0
[-0, 0] => 0
[-0.0, 0] => 0
[-0.0000, 0] => 0
PHP_ROUND_HALF_DOWN: result is same to PHP_ROUND_HALF_UP
PHP_ROUND_HALF_EVEN: result is same to PHP_ROUND_HALF_UP
PHP_ROUND_HALF_ODD: result is same to PHP_ROUND_HALF_UP
PHP_ROUND_FLOOR: result is same to PHP_ROUND_HALF_UP
PHP_ROUND_CEILING: result is same to PHP_ROUND_HALF_UP
PHP_ROUND_AWAY_FROM_ZERO: result is same to PHP_ROUND_HALF_UP
PHP_ROUND_TOWARD_ZERO: result is same to PHP_ROUND_HALF_UP

View file

@ -0,0 +1,28 @@
--TEST--
bcround() function with error
--EXTENSIONS--
bcmath
--FILE--
<?php
try {
bcround('hoge');
} catch (Throwable $e) {
echo $e->getMessage()."\n";
}
try {
bcround('0.00.1');
} catch (Throwable $e) {
echo $e->getMessage()."\n";
}
try {
bcround('0.001', 0, 1000);
} catch (Throwable $e) {
echo $e->getMessage()."\n";
}
?>
--EXPECT--
bcround(): Argument #1 ($num) is not well-formed
bcround(): Argument #1 ($num) is not well-formed
bcround(): Argument #3 ($mode) must be a valid rounding mode (PHP_ROUND_*)

View file

@ -0,0 +1,89 @@
--TEST--
bcround() function PHP_ROUND_FLOOR
--EXTENSIONS--
bcmath
--FILE--
<?php
require_once __DIR__ . '/bcround_test_helper.inc';
run_round_test(PHP_ROUND_FLOOR);
?>
--EXPECT--
========== non-boundary value ==========
[1.1, 0] => 1
[1.2, 0] => 1
[1.3, 0] => 1
[1.4, 0] => 1
[1.6, 0] => 1
[1.7, 0] => 1
[1.8, 0] => 1
[1.9, 0] => 1
[-1.1, 0] => -2
[-1.2, 0] => -2
[-1.3, 0] => -2
[-1.4, 0] => -2
[-1.6, 0] => -2
[-1.7, 0] => -2
[-1.8, 0] => -2
[-1.9, 0] => -2
========== minus precision ==========
[50, -2] => 0
[-50, -2] => -100
[1230, -1] => 1230
[1235, -1] => 1230
[-1230, -1] => -1230
[-1235, -1] => -1240
[3400.0000, -2] => 3400
[3400.0001, -2] => 3400
[3450.0000, -2] => 3400
[3450.0001, -2] => 3400
[-3400.0000, -2] => -3400
[-3400.0001, -2] => -3500
[-3450.0000, -2] => -3500
[-3450.0001, -2] => -3500
========== zero precision ==========
[1235, 0] => 1235
[1235.0, 0] => 1235
[1235.000001, 0] => 1235
[1235.5, 0] => 1235
[1235.500001, 0] => 1235
[-1235, 0] => -1235
[-1235.0, 0] => -1235
[-1235.000001, 0] => -1236
[-1235.5, 0] => -1236
[-1235.500001, 0] => -1236
[0.0001, 0] => 0
[0.5, 0] => 0
[0.5000, 0] => 0
[0.5001, 0] => 0
[-0.0001, 0] => -1
[-0.5, 0] => -1
[-0.5000, 0] => -1
[-0.5001, 0] => -1
========== plus precision ==========
[28.40, 1] => 28.4
[28.4000001, 1] => 28.4
[28.45, 1] => 28.4
[28.4500001, 1] => 28.4
[-28.40, 1] => -28.4
[-28.4000001, 1] => -28.5
[-28.45, 1] => -28.5
[-28.4500001, 1] => -28.5
[153.90, 1] => 153.9
[153.9000001, 1] => 153.9
[153.95, 1] => 153.9
[153.9500001, 1] => 153.9
[-153.90, 1] => -153.9
[-153.9000001, 1] => -154.0
[-153.95, 1] => -154.0
[-153.9500001, 1] => -154.0
[0.000001, 3] => 0.000
[0.0005, 3] => 0.000
[0.000500, 3] => 0.000
[0.000501, 3] => 0.000
[-0.000001, 3] => -0.001
[-0.0005, 3] => -0.001
[-0.000500, 3] => -0.001
[-0.000501, 3] => -0.001

View file

@ -0,0 +1,89 @@
--TEST--
bcround() function PHP_ROUND_HALF_DOWN
--EXTENSIONS--
bcmath
--FILE--
<?php
require_once __DIR__ . '/bcround_test_helper.inc';
run_round_test(PHP_ROUND_HALF_DOWN);
?>
--EXPECT--
========== non-boundary value ==========
[1.1, 0] => 1
[1.2, 0] => 1
[1.3, 0] => 1
[1.4, 0] => 1
[1.6, 0] => 2
[1.7, 0] => 2
[1.8, 0] => 2
[1.9, 0] => 2
[-1.1, 0] => -1
[-1.2, 0] => -1
[-1.3, 0] => -1
[-1.4, 0] => -1
[-1.6, 0] => -2
[-1.7, 0] => -2
[-1.8, 0] => -2
[-1.9, 0] => -2
========== minus precision ==========
[50, -2] => 0
[-50, -2] => 0
[1230, -1] => 1230
[1235, -1] => 1230
[-1230, -1] => -1230
[-1235, -1] => -1230
[3400.0000, -2] => 3400
[3400.0001, -2] => 3400
[3450.0000, -2] => 3400
[3450.0001, -2] => 3500
[-3400.0000, -2] => -3400
[-3400.0001, -2] => -3400
[-3450.0000, -2] => -3400
[-3450.0001, -2] => -3500
========== zero precision ==========
[1235, 0] => 1235
[1235.0, 0] => 1235
[1235.000001, 0] => 1235
[1235.5, 0] => 1235
[1235.500001, 0] => 1236
[-1235, 0] => -1235
[-1235.0, 0] => -1235
[-1235.000001, 0] => -1235
[-1235.5, 0] => -1235
[-1235.500001, 0] => -1236
[0.0001, 0] => 0
[0.5, 0] => 0
[0.5000, 0] => 0
[0.5001, 0] => 1
[-0.0001, 0] => 0
[-0.5, 0] => 0
[-0.5000, 0] => 0
[-0.5001, 0] => -1
========== plus precision ==========
[28.40, 1] => 28.4
[28.4000001, 1] => 28.4
[28.45, 1] => 28.4
[28.4500001, 1] => 28.5
[-28.40, 1] => -28.4
[-28.4000001, 1] => -28.4
[-28.45, 1] => -28.4
[-28.4500001, 1] => -28.5
[153.90, 1] => 153.9
[153.9000001, 1] => 153.9
[153.95, 1] => 153.9
[153.9500001, 1] => 154.0
[-153.90, 1] => -153.9
[-153.9000001, 1] => -153.9
[-153.95, 1] => -153.9
[-153.9500001, 1] => -154.0
[0.000001, 3] => 0.000
[0.0005, 3] => 0.000
[0.000500, 3] => 0.000
[0.000501, 3] => 0.001
[-0.000001, 3] => 0.000
[-0.0005, 3] => 0.000
[-0.000500, 3] => 0.000
[-0.000501, 3] => -0.001

View file

@ -0,0 +1,89 @@
--TEST--
bcround() function PHP_ROUND_HALF_EVEN
--EXTENSIONS--
bcmath
--FILE--
<?php
require_once __DIR__ . '/bcround_test_helper.inc';
run_round_test(PHP_ROUND_HALF_EVEN);
?>
--EXPECT--
========== non-boundary value ==========
[1.1, 0] => 1
[1.2, 0] => 1
[1.3, 0] => 1
[1.4, 0] => 1
[1.6, 0] => 2
[1.7, 0] => 2
[1.8, 0] => 2
[1.9, 0] => 2
[-1.1, 0] => -1
[-1.2, 0] => -1
[-1.3, 0] => -1
[-1.4, 0] => -1
[-1.6, 0] => -2
[-1.7, 0] => -2
[-1.8, 0] => -2
[-1.9, 0] => -2
========== minus precision ==========
[50, -2] => 0
[-50, -2] => 0
[1230, -1] => 1230
[1235, -1] => 1240
[-1230, -1] => -1230
[-1235, -1] => -1240
[3400.0000, -2] => 3400
[3400.0001, -2] => 3400
[3450.0000, -2] => 3400
[3450.0001, -2] => 3500
[-3400.0000, -2] => -3400
[-3400.0001, -2] => -3400
[-3450.0000, -2] => -3400
[-3450.0001, -2] => -3500
========== zero precision ==========
[1235, 0] => 1235
[1235.0, 0] => 1235
[1235.000001, 0] => 1235
[1235.5, 0] => 1236
[1235.500001, 0] => 1236
[-1235, 0] => -1235
[-1235.0, 0] => -1235
[-1235.000001, 0] => -1235
[-1235.5, 0] => -1236
[-1235.500001, 0] => -1236
[0.0001, 0] => 0
[0.5, 0] => 0
[0.5000, 0] => 0
[0.5001, 0] => 1
[-0.0001, 0] => 0
[-0.5, 0] => 0
[-0.5000, 0] => 0
[-0.5001, 0] => -1
========== plus precision ==========
[28.40, 1] => 28.4
[28.4000001, 1] => 28.4
[28.45, 1] => 28.4
[28.4500001, 1] => 28.5
[-28.40, 1] => -28.4
[-28.4000001, 1] => -28.4
[-28.45, 1] => -28.4
[-28.4500001, 1] => -28.5
[153.90, 1] => 153.9
[153.9000001, 1] => 153.9
[153.95, 1] => 154.0
[153.9500001, 1] => 154.0
[-153.90, 1] => -153.9
[-153.9000001, 1] => -153.9
[-153.95, 1] => -154.0
[-153.9500001, 1] => -154.0
[0.000001, 3] => 0.000
[0.0005, 3] => 0.000
[0.000500, 3] => 0.000
[0.000501, 3] => 0.001
[-0.000001, 3] => 0.000
[-0.0005, 3] => 0.000
[-0.000500, 3] => 0.000
[-0.000501, 3] => -0.001

View file

@ -0,0 +1,89 @@
--TEST--
bcround() function PHP_ROUND_HALF_ODD
--EXTENSIONS--
bcmath
--FILE--
<?php
require_once __DIR__ . '/bcround_test_helper.inc';
run_round_test(PHP_ROUND_HALF_ODD);
?>
--EXPECT--
========== non-boundary value ==========
[1.1, 0] => 1
[1.2, 0] => 1
[1.3, 0] => 1
[1.4, 0] => 1
[1.6, 0] => 2
[1.7, 0] => 2
[1.8, 0] => 2
[1.9, 0] => 2
[-1.1, 0] => -1
[-1.2, 0] => -1
[-1.3, 0] => -1
[-1.4, 0] => -1
[-1.6, 0] => -2
[-1.7, 0] => -2
[-1.8, 0] => -2
[-1.9, 0] => -2
========== minus precision ==========
[50, -2] => 100
[-50, -2] => -100
[1230, -1] => 1230
[1235, -1] => 1230
[-1230, -1] => -1230
[-1235, -1] => -1230
[3400.0000, -2] => 3400
[3400.0001, -2] => 3400
[3450.0000, -2] => 3500
[3450.0001, -2] => 3500
[-3400.0000, -2] => -3400
[-3400.0001, -2] => -3400
[-3450.0000, -2] => -3500
[-3450.0001, -2] => -3500
========== zero precision ==========
[1235, 0] => 1235
[1235.0, 0] => 1235
[1235.000001, 0] => 1235
[1235.5, 0] => 1235
[1235.500001, 0] => 1236
[-1235, 0] => -1235
[-1235.0, 0] => -1235
[-1235.000001, 0] => -1235
[-1235.5, 0] => -1235
[-1235.500001, 0] => -1236
[0.0001, 0] => 0
[0.5, 0] => 1
[0.5000, 0] => 1
[0.5001, 0] => 1
[-0.0001, 0] => 0
[-0.5, 0] => -1
[-0.5000, 0] => -1
[-0.5001, 0] => -1
========== plus precision ==========
[28.40, 1] => 28.4
[28.4000001, 1] => 28.4
[28.45, 1] => 28.5
[28.4500001, 1] => 28.5
[-28.40, 1] => -28.4
[-28.4000001, 1] => -28.4
[-28.45, 1] => -28.5
[-28.4500001, 1] => -28.5
[153.90, 1] => 153.9
[153.9000001, 1] => 153.9
[153.95, 1] => 153.9
[153.9500001, 1] => 154.0
[-153.90, 1] => -153.9
[-153.9000001, 1] => -153.9
[-153.95, 1] => -153.9
[-153.9500001, 1] => -154.0
[0.000001, 3] => 0.000
[0.0005, 3] => 0.001
[0.000500, 3] => 0.001
[0.000501, 3] => 0.001
[-0.000001, 3] => 0.000
[-0.0005, 3] => -0.001
[-0.000500, 3] => -0.001
[-0.000501, 3] => -0.001

View file

@ -0,0 +1,89 @@
--TEST--
bcround() function PHP_ROUND_HALF_UP
--EXTENSIONS--
bcmath
--FILE--
<?php
require_once __DIR__ . '/bcround_test_helper.inc';
run_round_test(PHP_ROUND_HALF_UP);
?>
--EXPECT--
========== non-boundary value ==========
[1.1, 0] => 1
[1.2, 0] => 1
[1.3, 0] => 1
[1.4, 0] => 1
[1.6, 0] => 2
[1.7, 0] => 2
[1.8, 0] => 2
[1.9, 0] => 2
[-1.1, 0] => -1
[-1.2, 0] => -1
[-1.3, 0] => -1
[-1.4, 0] => -1
[-1.6, 0] => -2
[-1.7, 0] => -2
[-1.8, 0] => -2
[-1.9, 0] => -2
========== minus precision ==========
[50, -2] => 100
[-50, -2] => -100
[1230, -1] => 1230
[1235, -1] => 1240
[-1230, -1] => -1230
[-1235, -1] => -1240
[3400.0000, -2] => 3400
[3400.0001, -2] => 3400
[3450.0000, -2] => 3500
[3450.0001, -2] => 3500
[-3400.0000, -2] => -3400
[-3400.0001, -2] => -3400
[-3450.0000, -2] => -3500
[-3450.0001, -2] => -3500
========== zero precision ==========
[1235, 0] => 1235
[1235.0, 0] => 1235
[1235.000001, 0] => 1235
[1235.5, 0] => 1236
[1235.500001, 0] => 1236
[-1235, 0] => -1235
[-1235.0, 0] => -1235
[-1235.000001, 0] => -1235
[-1235.5, 0] => -1236
[-1235.500001, 0] => -1236
[0.0001, 0] => 0
[0.5, 0] => 1
[0.5000, 0] => 1
[0.5001, 0] => 1
[-0.0001, 0] => 0
[-0.5, 0] => -1
[-0.5000, 0] => -1
[-0.5001, 0] => -1
========== plus precision ==========
[28.40, 1] => 28.4
[28.4000001, 1] => 28.4
[28.45, 1] => 28.5
[28.4500001, 1] => 28.5
[-28.40, 1] => -28.4
[-28.4000001, 1] => -28.4
[-28.45, 1] => -28.5
[-28.4500001, 1] => -28.5
[153.90, 1] => 153.9
[153.9000001, 1] => 153.9
[153.95, 1] => 154.0
[153.9500001, 1] => 154.0
[-153.90, 1] => -153.9
[-153.9000001, 1] => -153.9
[-153.95, 1] => -154.0
[-153.9500001, 1] => -154.0
[0.000001, 3] => 0.000
[0.0005, 3] => 0.001
[0.000500, 3] => 0.001
[0.000501, 3] => 0.001
[-0.000001, 3] => 0.000
[-0.0005, 3] => -0.001
[-0.000500, 3] => -0.001
[-0.000501, 3] => -0.001

View file

@ -0,0 +1,108 @@
<?php
function printResult (array $cases, int $mode)
{
foreach ($cases as [$num, $precision]) {
echo str_pad("[{$num}, {$precision}]", 17, ' ', STR_PAD_LEFT), " => ", bcround($num, $precision, $mode), "\n";
}
echo "\n";
}
function run_round_test(int $mode)
{
$non_boundary_value_cases = [
['1.1', 0],
['1.2', 0],
['1.3', 0],
['1.4', 0],
['1.6', 0],
['1.7', 0],
['1.8', 0],
['1.9', 0],
['-1.1', 0],
['-1.2', 0],
['-1.3', 0],
['-1.4', 0],
['-1.6', 0],
['-1.7', 0],
['-1.8', 0],
['-1.9', 0],
];
$minus_precision_cases = [
['50', -2],
['-50', -2],
['1230', -1],
['1235', -1],
['-1230', -1],
['-1235', -1],
['3400.0000', -2],
['3400.0001', -2],
['3450.0000', -2],
['3450.0001', -2],
['-3400.0000', -2],
['-3400.0001', -2],
['-3450.0000', -2],
['-3450.0001', -2],
];
$zero_precision_cases = [
['1235', 0],
['1235.0', 0],
['1235.000001', 0],
['1235.5', 0],
['1235.500001', 0],
['-1235', 0],
['-1235.0', 0],
['-1235.000001', 0],
['-1235.5', 0],
['-1235.500001', 0],
['0.0001', 0],
['0.5', 0],
['0.5000', 0],
['0.5001', 0],
['-0.0001', 0],
['-0.5', 0],
['-0.5000', 0],
['-0.5001', 0],
];
$plus_precision_cases = [
['28.40', 1],
['28.4000001', 1],
['28.45', 1],
['28.4500001', 1],
['-28.40', 1],
['-28.4000001', 1],
['-28.45', 1],
['-28.4500001', 1],
['153.90', 1],
['153.9000001', 1],
['153.95', 1],
['153.9500001', 1],
['-153.90', 1],
['-153.9000001', 1],
['-153.95', 1],
['-153.9500001', 1],
['0.000001', 3],
['0.0005', 3],
['0.000500', 3],
['0.000501', 3],
['-0.000001', 3],
['-0.0005', 3],
['-0.000500', 3],
['-0.000501', 3],
];
echo "========== non-boundary value ==========\n";
printResult($non_boundary_value_cases, $mode);
echo "========== minus precision ==========\n";
printResult($minus_precision_cases, $mode);
echo "========== zero precision ==========\n";
printResult($zero_precision_cases, $mode);
echo "========== plus precision ==========\n";
printResult($plus_precision_cases, $mode);
}

View file

@ -0,0 +1,89 @@
--TEST--
bcround() function PHP_ROUND_TOWARD_ZERO
--EXTENSIONS--
bcmath
--FILE--
<?php
require_once __DIR__ . '/bcround_test_helper.inc';
run_round_test(PHP_ROUND_TOWARD_ZERO);
?>
--EXPECT--
========== non-boundary value ==========
[1.1, 0] => 1
[1.2, 0] => 1
[1.3, 0] => 1
[1.4, 0] => 1
[1.6, 0] => 1
[1.7, 0] => 1
[1.8, 0] => 1
[1.9, 0] => 1
[-1.1, 0] => -1
[-1.2, 0] => -1
[-1.3, 0] => -1
[-1.4, 0] => -1
[-1.6, 0] => -1
[-1.7, 0] => -1
[-1.8, 0] => -1
[-1.9, 0] => -1
========== minus precision ==========
[50, -2] => 0
[-50, -2] => 0
[1230, -1] => 1230
[1235, -1] => 1230
[-1230, -1] => -1230
[-1235, -1] => -1230
[3400.0000, -2] => 3400
[3400.0001, -2] => 3400
[3450.0000, -2] => 3400
[3450.0001, -2] => 3400
[-3400.0000, -2] => -3400
[-3400.0001, -2] => -3400
[-3450.0000, -2] => -3400
[-3450.0001, -2] => -3400
========== zero precision ==========
[1235, 0] => 1235
[1235.0, 0] => 1235
[1235.000001, 0] => 1235
[1235.5, 0] => 1235
[1235.500001, 0] => 1235
[-1235, 0] => -1235
[-1235.0, 0] => -1235
[-1235.000001, 0] => -1235
[-1235.5, 0] => -1235
[-1235.500001, 0] => -1235
[0.0001, 0] => 0
[0.5, 0] => 0
[0.5000, 0] => 0
[0.5001, 0] => 0
[-0.0001, 0] => 0
[-0.5, 0] => 0
[-0.5000, 0] => 0
[-0.5001, 0] => 0
========== plus precision ==========
[28.40, 1] => 28.4
[28.4000001, 1] => 28.4
[28.45, 1] => 28.4
[28.4500001, 1] => 28.4
[-28.40, 1] => -28.4
[-28.4000001, 1] => -28.4
[-28.45, 1] => -28.4
[-28.4500001, 1] => -28.4
[153.90, 1] => 153.9
[153.9000001, 1] => 153.9
[153.95, 1] => 153.9
[153.9500001, 1] => 153.9
[-153.90, 1] => -153.9
[-153.9000001, 1] => -153.9
[-153.95, 1] => -153.9
[-153.9500001, 1] => -153.9
[0.000001, 3] => 0.000
[0.0005, 3] => 0.000
[0.000500, 3] => 0.000
[0.000501, 3] => 0.000
[-0.000001, 3] => 0.000
[-0.0005, 3] => 0.000
[-0.000500, 3] => 0.000
[-0.000501, 3] => 0.000

View file

@ -28,6 +28,7 @@ PHPAPI void _php_math_basetozval(zend_string *str, int base, zval *ret);
PHPAPI zend_string * _php_math_zvaltobase(zval *arg, int base);
#include <math.h>
#include "php_math_round_mode.h"
#ifndef M_E
#define M_E 2.7182818284590452354 /* e */
@ -97,37 +98,4 @@ PHPAPI zend_string * _php_math_zvaltobase(zval *arg, int base);
#define M_SQRT3 1.73205080756887729352 /* sqrt(3) */
#endif
/* Define rounding modes (all are round-to-nearest) */
#ifndef PHP_ROUND_HALF_UP
#define PHP_ROUND_HALF_UP 0x01 /* Arithmetic rounding, up == away from zero */
#endif
#ifndef PHP_ROUND_HALF_DOWN
#define PHP_ROUND_HALF_DOWN 0x02 /* Arithmetic rounding, down == towards zero */
#endif
#ifndef PHP_ROUND_HALF_EVEN
#define PHP_ROUND_HALF_EVEN 0x03 /* Banker's rounding */
#endif
#ifndef PHP_ROUND_HALF_ODD
#define PHP_ROUND_HALF_ODD 0x04
#endif
#ifndef PHP_ROUND_CEILING
#define PHP_ROUND_CEILING 0x05
#endif
#ifndef PHP_ROUND_FLOOR
#define PHP_ROUND_FLOOR 0x06
#endif
#ifndef PHP_ROUND_TOWARD_ZERO
#define PHP_ROUND_TOWARD_ZERO 0x07
#endif
#ifndef PHP_ROUND_AWAY_FROM_ZERO
#define PHP_ROUND_AWAY_FROM_ZERO 0x08
#endif
#endif /* PHP_MATH_H */

View file

@ -0,0 +1,49 @@
/*
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Jim Winstead <jimw@php.net> |
| Stig Sæther Bakken <ssb@php.net> |
+----------------------------------------------------------------------+
*/
/* Define rounding modes (all are round-to-nearest) */
#ifndef PHP_ROUND_HALF_UP
#define PHP_ROUND_HALF_UP 0x01 /* Arithmetic rounding, up == away from zero */
#endif
#ifndef PHP_ROUND_HALF_DOWN
#define PHP_ROUND_HALF_DOWN 0x02 /* Arithmetic rounding, down == towards zero */
#endif
#ifndef PHP_ROUND_HALF_EVEN
#define PHP_ROUND_HALF_EVEN 0x03 /* Banker's rounding */
#endif
#ifndef PHP_ROUND_HALF_ODD
#define PHP_ROUND_HALF_ODD 0x04
#endif
#ifndef PHP_ROUND_CEILING
#define PHP_ROUND_CEILING 0x05
#endif
#ifndef PHP_ROUND_FLOOR
#define PHP_ROUND_FLOOR 0x06
#endif
#ifndef PHP_ROUND_TOWARD_ZERO
#define PHP_ROUND_TOWARD_ZERO 0x07
#endif
#ifndef PHP_ROUND_AWAY_FROM_ZERO
#define PHP_ROUND_AWAY_FROM_ZERO 0x08
#endif