Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's Int.MaxValue between friends?

The max values of int, float and long in Scala are:

Int.MaxValue = 2147483647

Float.MaxValue = 3.4028235E38

Long.MaxValue = 9223372036854775807L

From the authors of Scala compiler, Keynote, PNW Scala 2013, slide 16 What's Int.MaxValue between friends?:

val x1: Float = Long.MaxValue
val x2: Float = Long.MaxValue - Int.MaxValue
println (x1 == x2)

// NO WONDER NOTHING WORKS

Why does this expression return true?

like image 223
MiP Avatar asked Apr 26 '17 18:04

MiP


2 Answers

A Float is a 4-byte floating point value. Meanwhile a Long is an 8-byte value and an Int is also a 4-byte value. However, the way numbers are stored in 4-byte floating point values means that they have only around 8 digits of precision. Consequently, they do not have the capacity to store even the 4 most significant bytes (around 9-10 digits) of a Long regardless of the value of the least 4 significant bytes (another 9-10 digits).

Consequently, the Float representation of the two expressions is the same, because the bits that differ are below the resolution of a Float. Hence the two values compare equal.

like image 61
Mike Allen Avatar answered Oct 18 '22 01:10

Mike Allen


Echoing Mike Allen's answer, but hoping to provide some additional context (would've left this as a comment rather than a separate answer, but SO's reputation feature wouldn't let me).

Integers have a maximum range of values defined as either 0 to 2^n (if it is an unsigned integer) or -2^(n-1) to 2^(n-1) (for signed integers) where n is the number of bits in the underlying implementation (n=32 in this case). If you wish to represent a number larger than 2^31 with a signed value, you can't use an int. A signed long will work up to 2^63. For anything larger than this, a signed float can go up to roughly 2^127.

One other thing to note is that these resolution issues are only in force when the value stored in the floating point number approaches the max. In this case, the subtraction operation causes a change in true value that is many orders of magnitude smaller than the first value. A float would not round off the difference between 100 and 101, but it might round off the difference between 10000000000000000000000000000 and 10000000000000000000000000001.

Same goes for small values. If you cast 0.1 to an integer, you get exactly 0. This is not generally considered a failing of the integer data type.

If you are operating on numbers that are many orders of magnitude different in size, and also not able to tolerate rounding errors, you will need data structures and algorithms that account for inherent limitations of binary data representation. One possible solution would be to use a floating point encoding with fewer bits of exponential, thereby limiting the max value but providing for greater resolution is less significant bits. For greater detail, check out:

  • look up the IEEE Standard 754 (which defines the floating point encoding)
  • http://steve.hollasch.net/cgindex/coding/ieeefloat.html
  • https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
like image 32
Benjamin Avatar answered Oct 18 '22 00:10

Benjamin