Skip to content
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

[SR-3131] String(someDouble) incorrectly switches to scientific notation for large integers #45719

Closed
lilyball mannequin opened this issue Nov 3, 2016 · 18 comments
Closed
Assignees
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. CustomStringConvertible Area → standard library: The `CustomStringConvertible` protocol Double Area → standard library: The `Double` type duplicate Resolution: Duplicates another issue standard library Area: Standard library umbrella swift 3.0 unexpected behavior Bug: Unexpected behavior or incorrect output

Comments

@lilyball
Copy link
Mannequin

lilyball mannequin commented Nov 3, 2016

Previous ID SR-3131
Radar None
Original Reporter @lilyball
Type Bug
Status Resolved
Resolution Done
Environment

Apple Swift version 3.0.1 (swiftlang-800.0.58.6 clang-800.0.42.1)
Target: x86_64-apple-macosx10.9

Additional Detail from JIRA
Votes 0
Component/s Standard Library
Labels Bug
Assignee @tbkka
Priority Medium

md5: 1b1ce68db85995c555c91183810f4d55

duplicates:

Issue Description:

The string representation of a Double incorrectly uses scientific notation for large integers that are still within the range that can be precisely represented using a Double. This happens at some point between 1 << 49 and 1 << 50.

Example:

  1> Double(1 << 50)
$R0: Double = 1125899906842624
  2> Double(1 << 50).ulp
$R1: Double = 0.25
  3> print(Double(1 << 50))
1.12589990684262e+15
@tbkka
Copy link
Contributor

tbkka commented Feb 9, 2018

Using scientific notation is not really a bug here. The bug is simply that the final value has been printed with too few digits. This is the same root issue as #42728, apple/swift-corelibs-foundation#4412, and several others.

@tbkka
Copy link
Contributor

tbkka commented Mar 8, 2018

Kevin: Do you agree this is a duplicate of #42728?

@lilyball
Copy link
Mannequin Author

lilyball mannequin commented Mar 8, 2018

If we take it as a given that using scientific notation is fine and the only problem is it's using it too early, then yes.

However, I'm not sure I agree that using scientific notation in general isn't a problem. I'm concerned about the effect this might have when trying to produce a specific machine-readable output based on data that contains floating-point numbers. I suppose I'm willing to say that using scientific notation is ok, but we should have a mechanism that guarantees a non-scientific-notation string representation of a floating-point value as well (and String(format:…) is not sufficient as that's part of Foundation, not the stdlib).

@tbkka
Copy link
Contributor

tbkka commented Mar 16, 2018

The description and debugDescription properties explicitly try to produce short strings, so they will switch between scientific and decimal forms depending on the value. If scientific form is unacceptable for your application, then description and debugDescription are not appropriate.

@lilyball
Copy link
Mannequin Author

lilyball mannequin commented Mar 16, 2018

Since NumberFormatter doesn't exist in the Swift stdlib (it's part of Foundation), and for that matter, neither does String(format:), then String(someDouble) is the only way to get a string representation of a double using the stdlib. It should strive for accuracy and predictability.

@tbkka
Copy link
Contributor

tbkka commented Mar 17, 2018

It sounds like my forthcoming change for #42728 will address your concerns. It adds no new API to the stdlib (so it will not give you a way to request non-exponential format) but it does fix the current inconsistent and inaccurate formatting.

@tbkka
Copy link
Contributor

tbkka commented Apr 2, 2018

Please try this again with Swift master. I believe #15474 might have addressed your concern here.

@lilyball
Copy link
Mannequin Author

lilyball mannequin commented Apr 5, 2018

@tbkka I just tested with the swift-DEVELOPMENT-SNAPSHOT-2018-04-03-a toolchain, which looks like it contains your PR, and the bug is still there. print(Double(1 << 50)) prints 1.125899906842624e+15 instead of the expected 1125899906842624.

@tbkka
Copy link
Contributor

tbkka commented Apr 5, 2018

Thanks for checking that. The hard part is to determine the exact criteria that should be used. Once we can settle that, actually implementing it won't be hard. One possible criteria is shortness of the output. Certainly, your specific example is shorter without the exponential notation.

For reference, here is the code that decides between exponential and decimal formatting. As you can see, it currently only considers the base-10 exponent. That decision could be made more sophisticated, of course.

Any changes would affect these tests.

@lilyball
Copy link
Mannequin Author

lilyball mannequin commented Apr 5, 2018

Shortness is important, but clearly not the most important, because 1000 should not print as 1e2. I don't know where we should draw the line, but I do think that any integer value that can be exactly represented by a Double should be printed without exponential notation (which is what this particular ticket is about). A simple rationale here is this means the string representation of Double(exactly: Int) will always match the string representation of the original integer plus ".0", and I think that's a useful property.

@tbkka
Copy link
Contributor

tbkka commented Apr 5, 2018

Would you expect 10715086071862673209484250490600018105614048117055336074437503883703510511249361224931983788156958581275946729175531468251871452856923140435984577574698574803934567774824230985421074605062371141877954182153046474983581941267398767559165543946077062914571196477686542167660429831652624386837205668069376.0? This is an integer value that can be exactly represented as a Double.

Would it make sense to just change the existing cutoff to 2^53?

@lilyball
Copy link
Mannequin Author

lilyball mannequin commented Apr 5, 2018

Ok, let me rephrase. By "exactly represented as a Double" I actually meant "is in the contiguous range of integer values that are all exactly representable by a Double". I believe that range is -2<<52...2<<52.

@tbkka
Copy link
Contributor

tbkka commented Apr 5, 2018

In terms of unit tests, then, you would like to see the following for Float, Double, and Float80?

expectDescription("16777216.0", Float(1 << 24))
expectDescription("1.6777218e+7", Float(1 << 24).nextUp)
expectDescription("9007199254740992.0", Double(1 << 53))
expectDescription("9.007199254740994e+15", Double(1 << 53).nextUp)
// `Float80(1 << 62) * 4.0` avoids integer overflows
expectDescription("18446744073709551616.0", Float80(1 << 62) * 4.0)
expectDescription("1.8446744073709551618e+19", (Float80(1 << 62) * 4.0).nextUp)

If you could verify these values, I'd greatly appreciate. It will be another week or so before I can get the PR together.

@lilyball
Copy link
Mannequin Author

lilyball mannequin commented Apr 5, 2018

Those values look good to me. I'd probably also add tests for the negative versions.

@tbkka
Copy link
Contributor

tbkka commented Apr 6, 2018

Please see #15805.

@lilyball
Copy link
Mannequin Author

lilyball mannequin commented Apr 7, 2018

Thanks for doing this!

@tbkka
Copy link
Contributor

tbkka commented Apr 12, 2018

The fix in #15805 has been merged.

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
@newbie-02
Copy link

old comment:

because 1000 should not print as 1e2.

no! - äh yes! ... you are right, it shouldn't ;-)

@AnthonyLatsis AnthonyLatsis added String Area → standard library: The `String` type unexpected behavior Bug: Unexpected behavior or incorrect output Double Area → standard library: The `Double` type swift 3.0 duplicate Resolution: Duplicates another issue labels May 26, 2023
@AnthonyLatsis AnthonyLatsis added CustomStringConvertible Area → standard library: The `CustomStringConvertible` protocol and removed String Area → standard library: The `String` type labels May 26, 2023
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. CustomStringConvertible Area → standard library: The `CustomStringConvertible` protocol Double Area → standard library: The `Double` type duplicate Resolution: Duplicates another issue standard library Area: Standard library umbrella swift 3.0 unexpected behavior Bug: Unexpected behavior or incorrect output
Projects
None yet
Development

No branches or pull requests

3 participants