I'm revisiting a question (How to test if numeric conversion will change value?) that as far as I was concerned was fully solved. The problem was to detect when a particular numeric value would overflow JavaScript's IEEE-754 Number type. The previous question was using C# and the marked answer worked perfectly.

Now I'm doing the exact same task but this time in Java and it doesn't work. AFAIK, Java uses IEEE-754 for its double data type. So I should be able to cast it back and forth to force the loss of precision but it round trips. Baffled by this I started poking deeper in Java and now I'm really confused.

In both C# and Java, the min and max values for long are the same:

```
long MIN_VALUE = -9223372036854775808L;
long MAX_VALUE = 9223372036854775807L;
```

AFAIK, these values are outside the representable numbers in IEEE-754 because of the fixed bits reserved for the exponent and sign.

```
// this fails in browsers that have stuck with the pure ECMAScript Number format
var str = Number(-9223372036854775808).toFixed();
if ("-9223372036854775808" !== str) { throw new Error("Overflow!"); }
```

This returns `false`

for (value = -9223372036854775808L) in Java:

```
boolean invalidIEEE754(long value) {
try {
return ((long)((double)value)) != value;
} catch (Exception ex) {
return true;
}
}
```

This returns `false`

for (value = -9223372036854775808L) in Java:

```
boolean invalidIEEE754(long value) {
// trying to get closer to the actual representation and
// being more explicit about conversions
long bits = Double.doubleToLongBits(Long.valueOf(value).doubleValue());
long roundtrip = Double.valueOf(Double.longBitsToDouble(bits)).longValue();
return (value != roundtrip);
}
```

This returns `true`

for (value = -9223372036854775808L) but is less accurate:

```
boolean invalidIEEE754(long value) {
return (0x0L != (0xFFF0000000000000L & (value < 0L ? -value : value)));
}
```

Why does this work this way? Am I missing something like compiler optimization, e.g. is the compiler detecting my conversions and "fixing" them for me?

**Edit:** Adding test case by request. All three of these tests fail:

```
import static org.junit.Assert.*;
import org.junit.Test;
public class FooTests {
@Test
public void ieee754One() {
assertTrue(((long)((double)Long.MIN_VALUE)) != Long.MIN_VALUE);
}
@Test
public void ieee754Two() {
long bits = Double.doubleToLongBits(Long.valueOf(Long.MIN_VALUE).doubleValue());
long roundtrip = Double.valueOf(Double.longBitsToDouble(bits)).longValue();
assertTrue(Long.MIN_VALUE != roundtrip);
}
@Test
public void ieee754Three() {
long bits = Double.doubleToRawLongBits(Long.valueOf(Long.MIN_VALUE).doubleValue());
long roundtrip = Double.valueOf(Double.longBitsToDouble(bits)).longValue();
assertTrue(Long.MIN_VALUE != roundtrip);
}
}
```

`-9223372036854775808L`

**is** representable as an IEEE-754 double-precision number. It is exactly `-2^63`

, which has the double representation `-1.0 x 2^63`

and encoding `0xc3e0000000000000`

.

Double is capable of representing numbers much, much larger than this. However, it is not capable of representing *all integers* in the range of representable numbers. For example, if you add one to the number, you will get `-9223372036854775807 = -2^63 + 1`

, which is *not* representable as a double-precision value, and will not survive the round-trip conversion.

Converting `-2^63 + 1`

to double will round it to the nearest representable double value, which is `-2^63`

; conversion back to long will preserve that value.

**Edit:** What platform did you do you JavaScript test on? In current Safari,

```
"-9223372036854775808" === Number(-9223372036854775808).toFixed()
```

evaluates as `True`

.

©2020 All rights reserved.