Skip to content
Open
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: 13 additions & 0 deletions ext/standard/formatted_print.c
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,19 @@ php_sprintf_appenddouble(zend_string **buffer, size_t *pos,
s = php_conv_fp((fmt == 'f')?'F':fmt, number, 0, precision,
(fmt == 'f')?LCONV_DECIMAL_POINT:'.',
&is_negative, &num_buf[1], &s_len);
/* Prevent negative sign when value rounds to zero (GH-12237) */
if (is_negative) {
double rounded;
if (fmt == 'f' || fmt == 'F') {
double factor = pow(10.0, (double)precision);
rounded = round(fabs(number) * factor) / factor;
} else {
rounded = fabs(number);
}
if (rounded == 0.0) {
is_negative = false;
}
}
if (is_negative) {
num_buf[0] = '-';
s = num_buf;
Expand Down
107 changes: 107 additions & 0 deletions ext/standard/tests/strings/gh12237.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
--TEST--
GH-12237 (printf/sprintf should not produce negative zero)
--FILE--
<?php

// Basic case from the bug report
echo "-- Basic case --\n";
var_dump(sprintf('%.2f', -0.001));
var_dump(sprintf('%.2f', -0.0));

// Various precisions where the value rounds to zero
echo "-- Precisions rounding to zero --\n";
var_dump(sprintf('%.0f', -0.1));
var_dump(sprintf('%.0f', -0.0));
var_dump(sprintf('%.1f', -0.04));
var_dump(sprintf('%.1f', -0.001));
var_dump(sprintf('%.2f', -0.004));
var_dump(sprintf('%.2f', -0.001));
var_dump(sprintf('%.3f', -0.0004));
var_dump(sprintf('%.3f', -0.0001));
var_dump(sprintf('%.4f', -0.00004));
var_dump(sprintf('%.4f', -0.00001));

// Values that should remain negative (do NOT round to zero)
echo "-- Should stay negative --\n";
var_dump(sprintf('%.2f', -0.01));
var_dump(sprintf('%.2f', -0.1));
var_dump(sprintf('%.2f', -1.5));
var_dump(sprintf('%.1f', -0.1));
var_dump(sprintf('%.0f', -1.0));

// Uppercase F format
echo "-- Uppercase F --\n";
var_dump(sprintf('%.2F', -0.001));
var_dump(sprintf('%.2F', -0.01));

// Explicit positive sign should show + when value rounds to zero
echo "-- Explicit sign --\n";
var_dump(sprintf('%+.2f', -0.001));
var_dump(sprintf('%+.2f', 0.001));
var_dump(sprintf('%+.2f', -0.01));

// printf output (not just sprintf)
echo "-- printf --\n";
printf('%.2f', -0.001);
echo "\n";
printf('%.2f', -0.01);
echo "\n";

// Consistency with number_format
echo "-- number_format consistency --\n";
var_dump(number_format(-0.001, 2));
var_dump(number_format(-0.01, 2));

// Very small negative values that round to zero
echo "-- Very small negatives --\n";
var_dump(sprintf('%.2f', -1e-10));
var_dump(sprintf('%.2f', -PHP_FLOAT_EPSILON));
var_dump(sprintf('%.2f', -1e-100));

// Padding and width
echo "-- Padding --\n";
var_dump(sprintf('%08.2f', -0.001));
var_dump(sprintf('%08.2f', -0.01));

?>
--EXPECT--
-- Basic case --
string(4) "0.00"
string(4) "0.00"
-- Precisions rounding to zero --
string(1) "0"
string(1) "0"
string(3) "0.0"
string(3) "0.0"
string(4) "0.00"
string(4) "0.00"
string(5) "0.000"
string(5) "0.000"
string(6) "0.0000"
string(6) "0.0000"
-- Should stay negative --
string(5) "-0.01"
string(5) "-0.10"
string(5) "-1.50"
string(4) "-0.1"
string(2) "-1"
-- Uppercase F --
string(4) "0.00"
string(5) "-0.01"
-- Explicit sign --
string(5) "+0.00"
string(5) "+0.00"
string(5) "-0.01"
-- printf --
0.00
-0.01
-- number_format consistency --
string(4) "0.00"
string(5) "-0.01"
-- Very small negatives --
string(4) "0.00"
string(4) "0.00"
string(4) "0.00"
-- Padding --
string(8) "00000.00"
string(8) "-0000.01"
36 changes: 18 additions & 18 deletions ext/standard/tests/strings/sprintf_variation9.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -336,15 +336,15 @@ string(8) "0.000000"
string(30) " 0.000000"

-- Iteration 26 --
string(9) "-0.000000"
string(9) "-0.000000"
string(10) " -0.000000"
string(10) "-0.000000 "
string(10) " -0.000000"
string(10) "
-0.000000"
string(9) "-0.000000"
string(30) " -0.000000"
string(8) "0.000000"
string(8) "0.000000"
string(9) " 0.000000"
string(9) "0.000000 "
string(9) " 0.000000"
string(9) "
0.000000"
string(8) "0.000000"
string(30) " 0.000000"

-- Iteration 27 --
string(50) "5000000000000000069686058479707049565356032.000000"
Expand Down Expand Up @@ -380,13 +380,13 @@ string(8) "0.000000"
string(30) " 0.000000"

-- Iteration 30 --
string(9) "-0.000000"
string(9) "-0.000000"
string(10) " -0.000000"
string(10) "-0.000000 "
string(10) " -0.000000"
string(10) "
-0.000000"
string(9) "-0.000000"
string(30) " -0.000000"
string(8) "0.000000"
string(8) "0.000000"
string(9) " 0.000000"
string(9) "0.000000 "
string(9) " 0.000000"
string(9) "
0.000000"
string(8) "0.000000"
string(30) " 0.000000"
Done
4 changes: 2 additions & 2 deletions ext/standard/tests/strings/vprintf_variation5.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ int(28)
int(54)

-- Iteration 4 --
200000.0000 0.0000 -200000.000000 -0.0000
int(45)
200000.0000 0.0000 -200000.000000 0.0000
int(44)

-- Iteration 5 --
20000.000000 -1999999999999999879418332743206357172224.000000 0.000000 20000000000000000000.000000
Expand Down
Loading