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

math/big: Float.Float32() does not correctly handle denormals that are rounded up to a power of 2 #14553

Closed
tarm opened this issue Feb 28, 2016 · 8 comments
Milestone

Comments

@tarm
Copy link

tarm commented Feb 28, 2016

Context for this issue is https://groups.google.com/forum/#!topic/golang-dev/8xrGLS6mzzE

It appears to be a bug in the rounding of big.Float.Float32() and
Float64(), which the compiler uses to convert constants to float32 and
float64.

Specifically the bug happens when 1) the float32/64 constant is a
tiny, denormal value, 2) the arbitrary precision value would have to
round up to a bit representation with more precision. So for example
0x7.9p-149 should round up to 0x8.0p-149 when converted to a float32,
but the existing code actually gets stuck at 3 bits of precision while
still overflowing the mantissa so 0x4.0p-149 is actually what gets
assigned (which is worse than rounding down to 0x7.0p-149).

Here is a playground link that shows the problem:
http://play.golang.org/p/_aMEvOuOAs

To be fair, several places in the git commit history and in the
comments discuss how math.Float does not completely handle denormal
values. On the other hand, it seems like the compiler should be able
to parse and assign them properly.

go v1.6, linux, x64

@bradfitz bradfitz changed the title big.Float.Float32() does not correctly handle denormals that are rounded up to a power of 2 math/big: Float.Float32() does not correctly handle denormals that are rounded up to a power of 2 Feb 28, 2016
@bradfitz bradfitz added this to the Go1.7 milestone Feb 28, 2016
@tarm
Copy link
Author

tarm commented Feb 28, 2016

I think have a working patch for it now. Not the most elegant though, so I would appreciate Robert's review.

@gopherbot
Copy link

CL https://golang.org/cl/20012 mentions this issue.

@tarm
Copy link
Author

tarm commented Mar 3, 2016

Robert, would you mind taking a look at the patch? I'm happy to rework it if you think there is a better way.

On Monday I'm going out of town for a couple weeks, so it would be great to get in before then.

@griesemer
Copy link
Contributor

Sure, will do, tomorrow.

  • gri

On Wed, Mar 2, 2016 at 8:32 PM, tarm notifications@github.com wrote:

Robert, would you mind taking a look at the patch? I'm happy to rework it
if you think there is a better way.

On Monday I'm going out of town for a couple weeks, so it would be great
to get in before then.


Reply to this email directly or view it on GitHub
#14553 (comment).

@griesemer
Copy link
Contributor

@tarm Apologies for the delay and thank you for your investigation and for providing test cases. That has been a good starting point for my own investigation. As an aside, independent of the git commit history, big.Float should handle denormals correctly, so this is clearly an issue that needs to be addressed.

Your analysis is not quite accurate: The whole point of rounding is to round to a given precision - there is no such thing as "rounding to a bit representation with more precision" in this context. Specifically, rounding is correct in this code.

What does happen though in these special denormal cases is that the exponent changes. This is what you call "bit representation with more precision", except that the precision doesn't change, but the exponent gets increased by one due to rounding.

The bug is that this exponent change is dropped on the floor in these case: if rounding "rounded up", the exponent increased but it is not considered anymore later. The correct fix is to recompute the precision available for the final denormal by looking at the new exponent again, rather than using r.prec when computing the mantissa.

Consequently, the actual fix is much simpler than suggested. I'll send out a CL in a little bit. See also my feedback on your CL (forthcoming).

@gopherbot
Copy link

CL https://golang.org/cl/20198 mentions this issue.

@gopherbot
Copy link

CL https://golang.org/cl/20199 mentions this issue.

@tarm
Copy link
Author

tarm commented Mar 4, 2016

Yes, my explanation was imprecise. I agree with your description and you patch looks much cleaner.

Another way of thinking about it is that the float32 denormals have a constant exponent, but the rounding for in big.Float only has fixed precision rounding out of the box. So the Float32() code has to convert from fixed precision to fixed exponent in the denormal case.

gopherbot pushed a commit that referenced this issue Mar 4, 2016
The changes to internal/big are completely automatic
by running vendor.bash in that directory.

Also added respective test case.

For #14553.

Change-Id: I98b124bcc9ad9e9bd987943719be27864423cb5d
Reviewed-on: https://go-review.googlesource.com/20199
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
@golang golang locked and limited conversation to collaborators Mar 13, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants