Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions ext/standard/JitNumberFormat.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
use PHPCompiler\JIT\BasicBlockHelper;
use PHPCompiler\JIT\Builtin\TypeErrorRaise;
use PHPCompiler\JIT\Context;
use PHPCompiler\JIT\JitStringBuiltinArg;
use PHPCompiler\JIT\JitRoundModeArg;
use PHPCompiler\JIT\JitStringBuiltinArg;
use PHPCompiler\JIT\JitValueBox;
use PHPCompiler\JIT\NamedOptionalCallArgs;
use PHPCompiler\JIT\Variable as JITVariable;
Expand All @@ -18,9 +18,9 @@
use PHPLLVM\Value;

/**
* LLVM JIT/AOT helper for number_format() (int/float/numeric string, 0–4 args; subset of PHP).
* LLVM JIT/AOT helper for number_format() (int/float/numeric string, 0–5 args; subset of PHP).
*
* php-src: ext/standard/number_format.c — Z_PARAM_LONG / Z_PARAM_STR
* php-src: ext/standard/number_format.c — Z_PARAM_LONG / Z_PARAM_STR / RoundingMode
*/
final class JitNumberFormat
{
Expand All @@ -29,9 +29,10 @@ public static function format(Context $context, JITVariable ...$args): Value
$argc = count($args);
$maxArgs = CompilerVersion::supportsRoundingModeEnum() ? 5 : 4;
if ($argc < 1 || $argc > $maxArgs) {
throw new \LogicException(
sprintf('number_format() requires one to %d arguments', $maxArgs)
);
throw new \LogicException(\sprintf(
'number_format() requires one to %d arguments',
$maxArgs
));
}

if ($context->callerStrictTypes) {
Expand Down
6 changes: 1 addition & 5 deletions ext/standard/VmNumberFormat.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,7 @@ public static function format(
$pow *= 10;
}

if ($decimals > 0) {
$rounded = VmRound::mathRound($number, $decimals, $roundingMode);
} else {
$rounded = VmRound::mathRound($number, 0, $roundingMode);
}
$rounded = VmRound::mathRound($number, $decimals, $roundingMode);

$intPart = (int) floor($rounded);
$fracPart = 0;
Expand Down
4 changes: 2 additions & 2 deletions ext/standard/number_format.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
/**
* number_format() for integers and floats (C-style locale subset; LLVM JIT/AOT).
*
* php-src: ext/standard/number_format.c — Z_PARAM_LONG / Z_PARAM_STR
* php-src: ext/standard/number_format.c — Z_PARAM_LONG / Z_PARAM_STR / RoundingMode
*/
final class number_format extends Internal
{
Expand Down Expand Up @@ -74,7 +74,7 @@ public function execute(Frame $frame): void
'number_format',
3,
'thousands_separator'
) ?? ','
) ?? ','
: ',';
$roundingMode = StdlibConstants::PHP_ROUND_HALF_UP;
if (CompilerVersion::supportsRoundingModeEnum() && isset($frame->calledArgs[4])) {
Expand Down
25 changes: 17 additions & 8 deletions test/compliance/cases/stdlib/number_format_rounding_mode.phpt
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
--TEST--
number_format() optional RoundingMode (PHP 8.4, #9438)
--EXTENSIONS--
stdlib number_format() optional rounding_mode (PHP 8.4, ext/standard/number_format.c, #9438)
--FILE--
<?php
if (!enum_exists('RoundingMode')) {
declare(strict_types=1);

if (!enum_exists('RoundingMode', false)) {
echo "skip\n";
exit(0);
}
echo number_format(1.55, 1, '.', '', RoundingMode::HalfAwayFromZero), "\n";
echo number_format(2.5, 0, '.', '', RoundingMode::HalfEven), "\n";
?>

var_export(number_format(2.5, 0, '.', '', RoundingMode::HalfAwayFromZero));
echo "\n";
var_export(number_format(2.5, 0, '.', '', RoundingMode::TowardsZero));
echo "\n";
var_export(number_format(1.55, 1, '.', '', RoundingMode::HalfAwayFromZero));
echo "\n";
var_export(number_format(2.5, 0, '.', '', RoundingMode::HalfEven));
echo "\n";
--EXPECT--
1.6
2
'3'
'2'
'1.6'
'2'
11 changes: 11 additions & 0 deletions test/compliance/cases/stdlib/number_format_rounding_mode_jit.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
--TEST--
stdlib number_format() optional rounding_mode JIT (#9438, ext/standard/number_format.c)
--FILE--
<?php
declare(strict_types=1);

echo number_format(2.5, 0, '.', '', RoundingMode::HalfAwayFromZero), "\n";
echo number_format(2.5, 0, '.', '', RoundingMode::TowardsZero), "\n";
--EXPECT--
3
2
11 changes: 11 additions & 0 deletions test/fixtures/aot/cases/number_format_rounding_mode.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
--TEST--
AOT: number_format() optional rounding_mode (#9438, ext/standard/number_format.c)
--FILE--
<?php
declare(strict_types=1);

echo number_format(2.5, 0, '.', '', RoundingMode::HalfAwayFromZero), "\n";
echo number_format(2.5, 0, '.', '', RoundingMode::TowardsZero), "\n";
--EXPECT--
3
2
28 changes: 20 additions & 8 deletions test/repro/maintainer_gap_number_format_rounding_mode.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,32 @@

declare(strict_types=1);

if (!enum_exists('RoundingMode')) {
fwrite(STDERR, "skip: RoundingMode not on reference profile\n");
if (!enum_exists('RoundingMode', false)) {
echo "skip: RoundingMode not on reference profile\n";
exit(0);
}

$got = number_format(1.55, 1, '.', '', RoundingMode::HalfAwayFromZero);
if ('1.6' !== $got) {
echo 'fail: got ', var_export($got, true), "\n";
$halfUp = number_format(2.5, 0, '.', '', RoundingMode::HalfAwayFromZero);
if ('3' !== $halfUp) {
echo 'fail: HalfAwayFromZero got ', var_export($halfUp, true), " expected '3'\n";
exit(1);
}

$gotEven = number_format(2.5, 0, '.', '', RoundingMode::HalfEven);
if ('2' !== $gotEven) {
echo 'fail even: got ', var_export($gotEven, true), "\n";
$towardsZero = number_format(2.5, 0, '.', '', RoundingMode::TowardsZero);
if ('2' !== $towardsZero) {
echo 'fail: TowardsZero got ', var_export($towardsZero, true), " expected '2'\n";
exit(1);
}

$oneDecimal = number_format(1.55, 1, '.', '', RoundingMode::HalfAwayFromZero);
if ('1.6' !== $oneDecimal) {
echo 'fail: 1.55/1 decimal got ', var_export($oneDecimal, true), " expected '1.6'\n";
exit(1);
}

$halfEven = number_format(2.5, 0, '.', '', RoundingMode::HalfEven);
if ('2' !== $halfEven) {
echo 'fail even: got ', var_export($halfEven, true), " expected '2'\n";
exit(1);
}

Expand Down
15 changes: 15 additions & 0 deletions test/unit/StringFormatRuntimeShrinkTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace PHPCompiler\Test\Unit;

use PHPCompiler\ext\standard\SprintfJitHelper;
use PHPCompiler\ext\standard\StdlibConstants;
use PHPCompiler\ext\standard\VmNumberFormat;
use PHPCompiler\ext\standard\VmSprintf;
use PHPUnit\Framework\TestCase;
Expand Down Expand Up @@ -47,5 +48,19 @@ public function testSprintfJitHelperNumberFormatMatchesVmNumberFormat(): void
SprintfJitHelper::numberFormat(1234.5, 2, '.', ',')
);
$this->assertSame('nan', SprintfJitHelper::numberFormat(NAN, 0, '.', ','));
$this->assertSame(
'3',
SprintfJitHelper::numberFormat(2.5, 0, '.', '', StdlibConstants::PHP_ROUND_HALF_UP)
);
$this->assertSame(
'2',
SprintfJitHelper::numberFormat(
2.5,
0,
'.',
'',
StdlibConstants::PHP_ROUND_TOWARD_ZERO
)
);
}
}