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

Loss of precision in Integer -> Float autocast #11710

Open
beta-ziliani opened this issue Jan 6, 2022 · 5 comments
Open

Loss of precision in Integer -> Float autocast #11710

beta-ziliani opened this issue Jan 6, 2022 · 5 comments
Labels
kind:bug A bug in the code. Does not apply to documentation, specs, etc. topic:compiler

Comments

@beta-ziliani
Copy link
Member

beta-ziliani commented Jan 6, 2022

When adding number autocast for 1.3.0, one key aspect of the design was to preserve the precision of numbers. That's why it's possible to cast an Int32 to a Float64, but not to Float32. However, literal autocasting might lose precision:

a : Float32 = 0
a = 33554435_i32
p a # prints 33554436.0

Probably the easiest fix it to see if for FloatN the literal integer fits in an (U)Int(N/2) or, better still, check the mantissa of the type, and raise an appropriate compilation error message.

@beta-ziliani beta-ziliani added kind:bug A bug in the code. Does not apply to documentation, specs, etc. topic:compiler labels Jan 6, 2022
@yxhuvud
Copy link
Contributor

yxhuvud commented Jan 6, 2022

That could detect the error but what should the action taken be? Compilation error?

@beta-ziliani
Copy link
Member Author

Thanks @yxhuvud , I updated the issue.

@straight-shoota
Copy link
Member

straight-shoota commented Jan 6, 2022

Yes, I think this should be a compilation error. If you don't care about integer precision, you wouldn't use an integer literal.

We should also consider Float32 to Float64 autocasting.

Float64's range is much bigger as well. Literals outside of Float32's range silently turn up as Infinity. That should certainly be a compiler error instead.

x : Float32
x = 1.7976931348623157e+308 # => Infinity

Additionally, Float64 has higher precision than Float32. The problem with floating point literals is that they are almost always losing precision.

0.99999999_f32 # => 1.0
0.99999999_f64 # => 0.99999999
0.99999999999999999_f64 # => 1.0

So it's clear that a float literal is never really precise. Even that precise looking 0.99999999 is not that exact decimal value, it's just very close to it.
Still, when using a literal explicitly typed as Float64, the expectation is to represent a floating point value with 64-bit precision. Not 32-bits. So I think an explicit Float64 literal should never autocast to Float32.

@straight-shoota
Copy link
Member

I realized the range problem isn't specific to autocasting, it also shows with regular literals:

1.7976931348623157e+308_f32 # => Infinity

@HertzDevil
Copy link
Contributor

Integer-to-float autocasting can also produce infinities for UInt128 to Float32:

def foo(x : Float32)
  x
end

foo 1_u128                                     # => 1.0
foo 0xFFFFFF00_00000000_00000000_00000000_u128 # => 3.4028235e+38
foo 0xFFFFFF7F_FFFFFFFF_FFFFFFFF_FFFFFFFF_u128 # => 3.4028235e+38
foo 0xFFFFFF80_00000000_00000000_00000000_u128 # => Infinity
foo 0xFFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_u128 # => Infinity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind:bug A bug in the code. Does not apply to documentation, specs, etc. topic:compiler
Projects
None yet
Development

No branches or pull requests

4 participants