bcmath番号のceil()、floor()、round()関数の正確な機能を模倣する必要があります。非常によく似た質問をすでに見つけましたが、残念ながら、提供された回答はサポートが不足しているため、十分ではありません。負の数の場合、round()関数の精度引数がありません。
誰かがこの問題のかなり短くてエレガントな解決策を思い付くことができるかどうか疑問に思いました。
すべての入力に感謝します、ありがとう!
bcmath番号のceil()、floor()、round()関数の正確な機能を模倣する必要があります。非常によく似た質問をすでに見つけましたが、残念ながら、提供された回答はサポートが不足しているため、十分ではありません。負の数の場合、round()関数の精度引数がありません。
誰かがこの問題のかなり短くてエレガントな解決策を思い付くことができるかどうか疑問に思いました。
すべての入力に感謝します、ありがとう!
この問題を解決しようとして夜を過ごした後、私はかなり簡単な解決策を見つけたと思います、ここにそれがあります:
function bcceil($number)
{
if (strpos($number, '.') !== false) {
if (preg_match("~\.[0]+$~", $number)) return bcround($number, 0);
if ($number[0] != '-') return bcadd($number, 1, 0);
return bcsub($number, 0, 0);
}
return $number;
}
function bcfloor($number)
{
if (strpos($number, '.') !== false) {
if (preg_match("~\.[0]+$~", $number)) return bcround($number, 0);
if ($number[0] != '-') return bcadd($number, 0, 0);
return bcsub($number, 1, 0);
}
return $number;
}
function bcround($number, $precision = 0)
{
if (strpos($number, '.') !== false) {
if ($number[0] != '-') return bcadd($number, '0.' . str_repeat('0', $precision) . '5', $precision);
return bcsub($number, '0.' . str_repeat('0', $precision) . '5', $precision);
}
return $number;
}
私は何も見逃していなかったと思います。誰かがバグを見つけたら教えてください。ここにいくつかのテストがあります:
assert(bcceil('4') == ceil('4')); // true
assert(bcceil('4.3') == ceil('4.3')); // true
assert(bcceil('9.999') == ceil('9.999')); // true
assert(bcceil('-3.14') == ceil('-3.14')); // true
assert(bcfloor('4') == floor('4')); // true
assert(bcfloor('4.3') == floor('4.3')); // true
assert(bcfloor('9.999') == floor('9.999')); // true
assert(bcfloor('-3.14') == floor('-3.14')); // true
assert(bcround('3', 0) == number_format('3', 0)); // true
assert(bcround('3.4', 0) == number_format('3.4', 0)); // true
assert(bcround('3.5', 0) == number_format('3.5', 0)); // true
assert(bcround('3.6', 0) == number_format('3.6', 0)); // true
assert(bcround('1.95583', 2) == number_format('1.95583', 2)); // true
assert(bcround('5.045', 2) == number_format('5.045', 2)); // true
assert(bcround('5.055', 2) == number_format('5.055', 2)); // true
assert(bcround('9.999', 2) == number_format('9.999', 2)); // true
以下は、丸めのための負の数と精度引数をサポートするものです。
function bcceil($val) {
if (($pos = strpos($val, '.')) !== false) {
if ($val[$pos+1] != 0 && $val[0] != '-')
return bcadd(substr($val, 0, $pos), 1, 0);
else
return substr($val, 0, $pos);
}
return $val;
}
function bcfloor($val) {
if (($pos = strpos($val, '.')) !== false) {
if ($val[$pos+1] != 0 && $val[0] == '-')
return bcsub(substr($val, 0, $pos), 1, 0);
else
return substr($val, 0, $pos);
}
return $val;
}
function bcround($val, $precision = 0) {
if (($pos = strpos($val, '.')) !== false) {
if ($precision > 0) {
$int = substr($val, 0, $pos);
$pos2 = ++$pos+$precision;
if ($pos2 < strlen($val)) {
$val2 = sprintf('%s.%s', substr($val, $pos, $pos2-$pos), substr($val, $pos2));
$val2 = $val2[0] >= 5 ? bcceil($val2) : bcfloor($val2);
if (strlen($val2) > $precision)
return bcadd($int, $val[0] == '-' ? -1 : 1, 0);
else
return sprintf('%s.%s', $int, rtrim($val2, '0'));
}
return $val;
} else {
if ($val[$pos+1] >= 5)
return ($val[0] == '-' ? bcfloor($val) : bcceil($val));
else
return ($val[0] == '-' ? bcceil($val) : bcfloor($val));
}
}
return $val;
}
これを行うには、bcmath 関数のみを使用します。
function bcceil($number, $precision = 0) {
$delta = bcdiv('9', bcpow(10, $precision + 1), $precision + 1);
$number = bcadd($number, $delta, $precision + 1);
$number = bcadd($number, '0', $precision);
return $number;
}
function bcfloor($number, $precision = 0) {
$number = bcadd($number, '0', $precision);
return $number;
}
テスト用:
$numbers = [
'1', '1.1', '1.4', '1.5', '1.9',
'1.01', '1.09', '1.10', '1.19', '1.90', '1.99',
'2'
];
foreach ($numbers as $n) {
printf("%s (ceil)--> %s\n", $n, bcceil($n, 1));
}
printf("\n");
foreach ($numbers as $n) {
printf("%s (floor)--> %s\n", $n, bcfloor($n, 1));
}
そしてテスト結果:
1 (ceil)--> 1.0
1.1 (ceil)--> 1.1
1.4 (ceil)--> 1.4
1.5 (ceil)--> 1.5
1.9 (ceil)--> 1.9
1.01 (ceil)--> 1.1
1.09 (ceil)--> 1.1
1.10 (ceil)--> 1.1
1.19 (ceil)--> 1.2
1.90 (ceil)--> 1.9
1.99 (ceil)--> 2.0
2 (ceil)--> 2.0
1 (floor)--> 1.0
1.1 (floor)--> 1.1
1.4 (floor)--> 1.4
1.5 (floor)--> 1.5
1.9 (floor)--> 1.9
1.01 (floor)--> 1.0
1.09 (floor)--> 1.0
1.10 (floor)--> 1.1
1.19 (floor)--> 1.1
1.90 (floor)--> 1.9
1.99 (floor)--> 1.9
2 (floor)--> 2.0