How to check if value is stored in double insert? (rounding yes, but truncating no)

I think the question is pretty straightforward. but here are some examples.

The example below is OK. I can round, and there were no truncations.

public static void main(String[] args) { double d = 9.9; long l = (long)d; System.out.println(l); } 

Output:

 9 

And now the number is out of the long range:

 public static void main(String[] args) { double d = 99999999999999999999999999999999.9; long l = (long)d; System.out.println(l); } 

Output:

 9223372036854775807 

That worries me. I can’t continue to work with a completely different number. I would rather get an error or exception.

Is there any way to detect this in Java?

+7
java double long-integer casting truncate
source share
2 answers

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; } 

A slightly more complex 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 rounding is done.

You may ask why strict inequality exists in fitsLong : d < Long.MAX_VALUE . In fact, this is because Long.MAX_VALUE itself cannot be represented as a double number. When you create (double)Long.MAX_VALUE , double does not have enough accuracy to represent it, so the closest represented value is selected, which is 9223372036854775808.0 ( Long_MAX_VALUE+1.0 ). Thus, he d <= Long.MAX_VALUE would return true for a number that is actually a little larger, since in this comparison the constant Long.MAX_VALUE raised to a double type. On the other hand, Long.MIN_VALUE can be exactly represented as a double , so here we have >= .

It is also interesting why the following works:

 double value = -9223372036854775809.9; // Long.MIN_VALUE-1.9 System.out.println(fitsLong(value)); // returns true 

This is because you have not actually read anything from Long.MIN_VALUE . Cm:

 double d1 = Long.MIN_VALUE; double d2 = -9223372036854775809.9; System.out.println(d1 == d2); // true 

Double precision is not enough to distinguish between -9223372036854775808 and -9223372036854775809.9 , so this is actually a double number. At compile time, it is converted to binary form, and the binary form is the same for these two numbers. Thus, by compiling the program, you cannot tell if -9223372036854775808 or -9223372036854775809.9 in the source code.

If you feel that there is still a problem, build BigDecimal from 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 
+12
source share

When you apply a floating point type to int or long , the result will be either the nearest integer (rounding to zero), or MIN_VALUE or MAX_VALUE for int or long , See JLS 5.1.3 .

Therefore, one of the alternatives would be to make typecast, and then check for the appropriate MIN_VALUE or MAX_VALUE .

Please note that Long.MAX_VALUE is 9223372036854775807 ... which is your test program number!

(However, this does not work if you produce a floating point type in byte, char or short . See the link above for an explanation.)

+1
source share

All Articles