You can compare it with Long.MIN_VALUE
and Long.MAX_VALUE
:
public static boolean fitsLong(double d) {
return d >= Long.MIN_VALUE && d < Long.MAX_VALUE;
}
Somewhat more sofisticated approach is to use BigDecimal
:
double value = 1234567.9;
long l = BigDecimal.valueOf(value)
.setScale(0, RoundingMode.HALF_EVEN)
.longValueExact(); // 1234568
double value = 99999999999999999999999999999999.9;
long l = BigDecimal.valueOf(value)
.setScale(0, RoundingMode.HALF_EVEN)
.longValueExact(); // ArithmeticException
This way you can control how the rounding is performed.
You may ask, why there's strict inequality in fitsLong
: d < Long.MAX_VALUE
. Actually that's because the Long.MAX_VALUE
itself cannot be represented as double number. When you cast (double)Long.MAX_VALUE
, there's not enough precision in double
type to represent it, so the closest representable value is selected which is 9223372036854775808.0
(Long_MAX_VALUE+1.0
). So were it d <= Long.MAX_VALUE
it would return true
for number which is actually a little bigger as in this comparison Long.MAX_VALUE
constant is promoted to double type. On the other hand Long.MIN_VALUE
can be exactly represented in double
type, thus here we have >=
.
Also it's interesting why the following works:
double value = -9223372036854775809.9; // Long.MIN_VALUE-1.9
System.out.println(fitsLong(value)); // returns true
That's because you actually did not subtract anything from the Long.MIN_VALUE
. See:
double d1 = Long.MIN_VALUE;
double d2 = -9223372036854775809.9;
System.out.println(d1 == d2); // true
The double precision is not enough to distinguish between -9223372036854775808
and -9223372036854775809.9
, so it's actually the same double number. During the compilation it's converted to binary form, and binary form for these two numbers is the same. Thus having compiled program you cannot distinguish whether -9223372036854775808
or -9223372036854775809.9
was in the source code.
If you feel that it's still the issue, construct the BigDecimal
from the String
:
long l = new BigDecimal("-9223372036854775808.2")
.setScale(0, RoundingMode.HALF_EVEN)
.longValueExact(); // ok, -9223372036854775808
long l = new BigDecimal("-9223372036854775808.9")
.setScale(0, RoundingMode.HALF_EVEN)
.longValueExact(); // ArithmeticException