Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.

Updating Number.Formatting to properly print -0 #19775

Merged
merged 3 commits into from
Sep 7, 2018
Merged

Updating Number.Formatting to properly print -0 #19775

merged 3 commits into from
Sep 7, 2018

Conversation

tannergooding
Copy link
Member

@tannergooding
Copy link
Member Author

FYI. @danmosemsft, @jkotas

This covers part of IEEE 754:2008 - 5.12.1: External character sequences representing zeros, infinities, and NaNs:

The conversions (described in 5.4.2) from supported formats to external character sequences and back that recover the original floating-point representation, shall recover zeros, infinities, and quiet NaNs, as well as non-zero finite numbers. In particular, signs of zeros and infinities are preserved

@tannergooding
Copy link
Member Author

tannergooding commented Aug 30, 2018

This fixes System.Double and System.Single. It also fixes System.Decimal, as that was the simpler change and I would believe is the desired behavior here as well.

This impacts 'R', as well as the other formats (such as 'G'). If we want to restrict this to just 'R', that will be a slightly more involved change.

@tannergooding
Copy link
Member Author

Looks like linux-musl is using a C runtime without signbit support, will fix.

-- Looking at CoreFX there doesn't appear to be existing code coverage for "R" or some of the special-cases (tests are still running locally to confirm I didn't just miss them). I'll work on getting those cases covered.

x Double-precision floating-point value

--*/
int __cdecl PAL_signbit(double x)
Copy link
Member Author

Choose a reason for hiding this comment

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

Had to add PAL_signbit.... Clang complains about importing fp.h and using FPDOUBLE to get the sign-bit, because the header also declares a static function which is unused in grisu3.cpp

Rather than fix the header or compilation flags, I opted to just use signbit, since it is the standard library function to do this.

Copy link
Member Author

@tannergooding tannergooding Aug 31, 2018

Choose a reason for hiding this comment

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

hmmm, looks like that won't work on all platforms, due to it being a #define sometimes (or I missed something)

Copy link
Member

Choose a reason for hiding this comment

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

You may need to add signbit to src/pal/src/include/pal/palinternal.h

Copy link
Member Author

Choose a reason for hiding this comment

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

Adding it to palinternal.h doesn't work in this case, because it is a macro in the math.h file.

I had to do what the other "macro" PAL redefinitions are doing (like isfinite and isnan), which is to define a new function (_signbit) which calls the macro, and then use the new function everywhere.
For the existing ones, the new function name was selected to match the MSVC function name (_finite, _isnan, etc). Since there is no _signbit function for MSVC (just signbit), I had to (for MSVC) also do #define signbit _signbit.

@tannergooding
Copy link
Member Author

Will go through the various CoreFX failures and make sure they are all expected.
Will then prep the PR which fixes them to be "correct" for after this is merged and gets pumped over.

@tannergooding
Copy link
Member Author

At least one of the failures is due to a bad change (specifically relating to integers). The break is in RoundNumber, which is used for rounding integers, decimals, and doubles/floats.

We are currently bypassing rounding (for decimal) in certain cases by passing an additional isDecimal parameter. There are a few ways I could fix this to keep the current behavior for integer and the new behavior for double/float. However, given that double/float also have special rounding rules (which RoundNumber doesn't currently handle), and that is may be good to generally track the original number "kind", I am working on a change that would allow NumberBuffer to carry around the "kind" (Unknown, Integer, Decimal, or Double) so that we can appropriately handle the various behaviors where necessary.

@tannergooding
Copy link
Member Author

System.Memory.Tests failures are because the UTF8String formatter also needs to be updated.

@tannergooding
Copy link
Member Author

Rebased to try and get jobs to run, most of them didn't kick off last time.

CoreFX side change is here: dotnet/corefx#32109

@eerhardt
Copy link
Member

eerhardt commented Sep 5, 2018

    internal unsafe ref struct NumberBuffer // needs to match layout of NUMBER in coreclr's src/classlibnative/bcltype/number.h

This comment seems out of date now. I don't see you updating the number.h file.


Refers to: src/System.Private.CoreLib/shared/System/Number.NumberBuffer.cs:16 in 5f66c17. [](commit_id = 5f66c17, deletion_comment = False)

@@ -488,6 +490,7 @@ private static string FormatSingle(ref ValueStringBuilder sb, float value, ReadO
char fmt = ParseFormatSpecifier(format, out int digits);
int precision = FloatPrecision;
NumberBuffer number = default;
number.kind = NumberBufferKind.Double;
Copy link
Member

Choose a reason for hiding this comment

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

Would it make more sense for NumberBufferKind.Double to be renamed to NumberBufferKind.FloatingPoint or similar? It feels odd to use Double when we are working with float/Single

Copy link
Member Author

Choose a reason for hiding this comment

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

Possibly, but I would like to do that as a follow-up PR.

Currently we use DoubleToNumber for both single and double.... We should probably either rename that as well, or add an explicit code-path for SingleToNumber

Copy link
Member

Choose a reason for hiding this comment

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

We are introducing the enum in this PR. Why not give it a good name from the start?

Copy link
Member Author

Choose a reason for hiding this comment

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

Because, until the the methods are split to handle Single explicitly, it is actually a NumberBuffer which contains a Double (Single is upcast in order to make the call) and so the name is more accurate as-is.

Copy link
Member

Choose a reason for hiding this comment

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

Ah, got it. That makes sense.

Copy link
Member

@eerhardt eerhardt left a comment

Choose a reason for hiding this comment

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

:shipit:

@tannergooding
Copy link
Member Author

This comment seems out of date now. I don't see you updating the number.h file

Fixed, added comments clarifying the expected offset of each field as well.

@tannergooding
Copy link
Member Author

Turns out the Windows x86 implementation was using a custom implementation written in assembly (that still used the x87 FPU stack).
I've removed that in the latest commit, in favor of the shared implementation under number.cpp (which was already used everywhere else).

@tannergooding
Copy link
Member Author

@danmosemsft, @jkotas, @eerhardt.

I believe all feedback has been resolved, but the PR has changed a bit since some of your approvals. I'd appreciate it if you could give it another cursory glance and sign-off again if everything looks good.

@danmoseley
Copy link
Member

Seems reasonable but this is not my area. It would be good for @jkotas to OK it.

@jkotas
Copy link
Member

jkotas commented Sep 6, 2018

The invalidated CoreFX tests need to be disabled to make the CI green.

@tannergooding
Copy link
Member Author

@jkotas, is there a file tracking those tests in CoreCLR, or do they need to be disabled in CoreFX directly?

@jkotas
Copy link
Member

jkotas commented Sep 6, 2018

Add them to: https://github.com/dotnet/coreclr/blob/master/tests/CoreFX/CoreFX.issues.json

@tannergooding
Copy link
Member Author

test Ubuntu x64 Checked jitstress1
test Ubuntu x64 Checked jitstress2

test Windows_NT x64 Checked jitstress1
test Windows_NT x64 Checked jitstress2

test Windows_NT x86 Checked jitstress1
test Windows_NT x86 Checked jitstress2

@tannergooding
Copy link
Member Author

Fixed the name of the CoreFX tests in the json file.

@tannergooding
Copy link
Member Author

@fiigii, the Avx2.Gather failures are unrelated. Could you take a look?

@tannergooding
Copy link
Member Author

@jkotas, any other feedback?

If not, this should be good to merge, the only failures are in the JitStress1 and JitStress2 jobs and are unrelated to the PR.

@tannergooding tannergooding merged commit 98fa2d6 into dotnet:master Sep 7, 2018
@fiigii
Copy link

fiigii commented Sep 7, 2018

@tannergooding I will look into this failure tomorrow, thanks.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Single.ToString and Double.ToString do not differentiate between -0.0 and +0.0
5 participants