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

reinterpret(Float16, 0x7bff) prints incorrect string #5948

Closed
ZviRackover opened this issue Feb 25, 2014 · 4 comments
Closed

reinterpret(Float16, 0x7bff) prints incorrect string #5948

ZviRackover opened this issue Feb 25, 2014 · 4 comments

Comments

@ZviRackover
Copy link

Reprorduced on:
Version 0.2.0 (2013-11-16 23:44 UTC)
Official http://julialang.org release
x86_64-w64-mingw32

0x7bff is the largest normal representation of Float16 which is 65504.0

julia> reinterpret(Float16, 0x7bff)
float16(65500.0)

julia> reinterpret(Uint16, float16(65504.0))
0x7bff

julia> reinterpret(Uint16, float16(65500.0))
0x7bfe

julia> reinterpret(Float16, 0x7bff) == float16(65504.0)
true

julia> reinterpret(Float16, 0x7bff) == float16(65500.0)
false

@ivarne
Copy link
Sponsor Member

ivarne commented Feb 25, 2014

The cause is that Float16 prints with only 4 significant digits (in base 10), and that makes printing and parsing not reversible. see: grisu.jl#L119 and grisu.jl#L26.

The problem is that binary floating point numbers often does not print nice as decimal fractions (eg Float64(0.1) would print exactly as "0.1000000000000000055511151231257827021181583404541015625"), so printing does not show a exact representation of the exact number, but the shortest base10 fraction that will parse back to the exact same Floating point value.

This could be fixed in 3 ways

  1. Implement a proper print_shortest mode for Float16.
  2. Change the number of digits to print to 5 (which in most cases will give redundant digits)
  3. Somehow change the rounding mode so that we get fewer of these collisions. Currently 38 % of the Float16 values does not parse back to the original value after being printed. That is strange because Float16 only have 3.311 decimal digits of internal precision, thus it should be possible to get unique 4 digit strings.
julia> function test()
           c = 0; d = 0
           f = nextfloat(-Inf16)
           while f != Inf16
               if float16(float64(string(f))) != f
                   c +=1
               end
               f = nextfloat(f); d +=1;
           end
           c,d
       end
test (generic function with 1 method)

julia> test()
(24366,63487)

julia> /(ans...)
0.3837951076598359

@ZviRackover
Copy link
Author

IMO 4 significant digits is too small to be reliable, especially for the integer part of the number (before the point)

@timholy
Copy link
Sponsor Member

timholy commented Feb 25, 2014

All of the collisions occur when the leading digit is 1. The problem is that
when the leading digit is a 1, you don't have the dynamic range; you
effectively have only 3 more digits to encode those 3.311 decimal-digits.

On my machine, your script reports errors on just 3.4% of Float16s.

--Tim

On Tuesday, February 25, 2014 02:44:06 AM Ivar Nesje wrote:

The cause is that Float16 prints with only 4 significant digits (in base
10), and that makes printing and parsing not reversible. see:
[grisu.jl#L119](https://github.com/JuliaLang/julia/blob/master/base/grisu.j
l#L119) and
[grisu.jl#L26](https://github.com/JuliaLang/julia/blob/master/base/grisu.jl
#L26).

The problem is that binary floating point numbers often does not print nice
as decimal fractions (eg Float64(0.1) would print exactly as
"0.1000000000000000055511151231257827021181583404541015625"), so printing
does not show a exact representation of the exact number, but the shortest
base10 fraction that will parse back to the exact same Floating point
value.

This could be fixed in 3 ways

  1. Implement a proper print_shortest mode for Float16.
  2. Change the number of digits to print to 5 (which in most cases will give
    redundant digits) 3. Somehow change the rounding mode so that we get fewer
    of these collisions. Currently 38 % of the Float16 values does not parse
    back to the original value after being printed. That is strange because
    Float16 only have 3.311 decimal digits of internal precision, thus it
    should be possible to get unique 4 digit strings.
julia> function test()
           c = 0; d = 0
           f = nextfloat(-Inf16)
           while f != Inf16
               if float16(float64(string(f))) != f
                   c +=1
               end
               f = nextfloat(f); d +=1;
           end
           c,d
       end
test (generic function with 1 method)

julia> test()
(24366,63487)

julia> /(ans...)
0.3837951076598359

Reply to this email directly or view it on GitHub:
#5948 (comment)

@StefanKarpinski
Copy link
Sponsor Member

I can't recall if the double-conversion library supports 16-bit floats. The core Grisu algorithm does, of course, support any precision of floating-point value. We might want to consider porting the algorithm to pure Julia at some point. It should really be all that difficult, I suspect, just kind of a pain.

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

No branches or pull requests

4 participants