Skip to content

number_format: zero out until negative decimals #13505

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from

Conversation

marc-mabe
Copy link
Contributor

On formatting big floating point numbers using number_format with negative decimal places the resulting number did not contain zeros for the decimal places requested to round due to how floating point numbers work.

This PR now explicitly zeros out these places so the resulting number is rounded for humans even so the closest floating point number would not. If you cast that back to floating point number you still get the same result.

Previously

printf("%s", number_format(1234567897576501234567.0, -5, "", "")); // 1234567897576501149696
printf("%f", (float)number_format(1234567897576501234567.0, -5, "", "")); // 1234567897576501149696.000000

After this change:

printf("%s", number_format(1234567897576501234567.0, -5, "", "")); // 1234567897576501100000
printf("%f", (float)number_format(1234567897576501234567.0, -5, "", "")); // 1234567897576501149696.000000

@@ -179,8 +179,8 @@ foreach ($numbers as $number) {
--- testing: float(9.223372036854776E+18)
... with precision 5: string(31) "9,223,372,036,854,775,808.00000"
... with precision 0: string(25) "9,223,372,036,854,775,808"
... with precision -1: string(25) "9,223,372,036,854,775,808"
... with precision -5: string(25) "9,223,372,036,854,800,384"
... with precision -1: string(25) "9,223,372,036,854,775,800"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
... with precision -1: string(25) "9,223,372,036,854,775,800"
... with precision -1: string(25) "9,223,372,036,854,775,810"

to be consistent with https://3v4l.org/ZGU7I

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mh I could try to use _php_math_number_format_long in case the rounded number fits long and decimal places are <= 0

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because of https://3v4l.org/SoS6N rounding it should be possible to check if the 1st rounded digit is 5-9

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The precision is too fine to make much sense in testing the rounding results for this case.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I misunderstood. Admittedly, it works a little differently than in 8.3. However, if the documentation is correct, the current behavior is more broken. We need to investigate a little more to see which is the correct behavior.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, I think it's too fine a precision to do rounding...
However, we need consistency in the specifications, so let's think a little about how we can make it more persuasive.

Copy link
Member

@SakiTakamachi SakiTakamachi Feb 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@marc-mabe
I thought about this for a bit, but if we want accurate results we should use BCMath. It makes no sense to round to such fine precision. It is not possible using normal methods.

As in the following example, the precision is such that it is difficult to even determine what the value received was intended in the first place.
https://3v4l.org/N6r4B

If the precision is so fine that rounding is not possible, I think your implementation is fine.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is for double only, for int it is ok - https://3v4l.org/5HqRt, so it seems ok for now

Copy link
Member

@SakiTakamachi SakiTakamachi Feb 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but it exceeds the "meaningful precision" of double.
(edit) In the first place, there is no point in comparing int and double. These are completely different data.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mvorisek formatting big floating point numbers still within the range of int are using the integer variant already (which internally uses unsigned long to be able to still round up). See #12333

@SakiTakamachi
Copy link
Member

LGTM

@marc-mabe
Copy link
Contributor Author

Damn I have done more testing and this approach can also break revert logic to floating point ...

$ ./sapi/cli/php -r 'printf("%f", (float)number_format(9223372036854775800.0, -9, "", ""));'
9223372036000000000.000000 
$ ./sapi/cli/php -r 'printf("%f", (float)number_format(9223372036854775800, -9, "", ""));'
9223372036999999488.000000

So I'm closing this one as it would need another solution.

@marc-mabe marc-mabe closed this Feb 27, 2024
@marc-mabe marc-mabe deleted the number_format-zero-dec branch June 16, 2024 07:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants