How to quickly check if a double float is suitable? (Java)

Are there any arithmetic or bitwise operations that can check whether the double falls into the float without loss of accuracy.

You should not only verify that the double range is in the range of the float, but also that no mantissa bits are lost.

Bye

PS: This answers the problem by half for C #: How to check if double can fit into float without converting to infinity But I need a solution that works in Java.

+6
source share
4 answers

A direct solution might look like this:

public class Scribble { public static void main(String[] args) { for (int i = 1; i <= 10; i++) { double d = 1d / ((double)i); float f = (float) d; boolean lossless = d == f; System.out.println(d + " can be converted " + (lossless ? "lossless" : "only with loss")); } } } 

output:

 1.0 can be converted lossless 0.5 can be converted lossless 0.3333333333333333 can be converted only with loss 0.25 can be converted lossless 0.2 can be converted only with loss 0.16666666666666666 can be converted only with loss 0.14285714285714285 can be converted only with loss 0.125 can be converted lossless 0.1111111111111111 can be converted only with loss 0.1 can be converted only with loss 

edit: speed comparison shows method2 seems to be the fastest:

  method1 | method2 | method3 237094654 | 209365345 | 468025911 214129288 | 209917275 | 448695709 232093486 | 197637245 | 448153336 249210162 | 200163771 | 460200921 240685446 | 200638561 | 447061763 332890287 | 337870633 | 450452194 247054322 | 199045232 | 449442540 235533069 | 200767924 | 452743201 256274670 | 199153775 | 453373979 298277375 | 198659529 | 456672251 229360115 | 205883096 | 454198291 252680123 | 224850463 | 452860277 246047739 | 200070587 | 458091501 304270790 | 204517093 | 463688631 235058620 | 204675812 | 448639390 260565871 | 205834286 | 458372075 256008432 | 242574024 | 498943242 311210028 | 208080237 | 478777466 242014926 | 208995343 | 457901380 239893559 | 205111348 | 451616471 

code:

 public class Scribble { static int size = 1024*1024*100; static boolean[] results = new boolean[size]; static double[] values = new double[size]; public static void main(String[] args) { // generate values for (int i = 0; i < size; i++) values[i] = 1d / ((double)i); long start; long duration; System.out.println(" method1 | method2 | method3 "); for (int i = 0; i < 20; i++) { start = System.nanoTime(); method1(size); duration = System.nanoTime() - start; System.out.printf("%9d", duration); start = System.nanoTime(); method2(size); duration = System.nanoTime() - start; System.out.printf(" | %9d", duration); start = System.nanoTime(); method3(size); duration = System.nanoTime() - start; System.out.printf(" | %9d\n", duration); } } private static void method1(int size) { boolean[] results = new boolean[size]; for (int i = 0; i < size; i++) { double d = values[i]; float f = (float) d; boolean lossless = d == f; results[i] = lossless; } } private static void method2(int size) { for (int i = 0; i < size; i++) { double d = values[i]; results[i] = d == (double)(float)d; } } private static void method3(int size) { for (int i = 0; i < size; i++) { double d = values[i]; results[i] = Double.compare(d, (float) d) == 0; } } } 
+6
source

How about this:

 double d = ...; if ((double)(float)d == d) { System.out.println(d + " fits into float!"); } 

The idea is quite simple: first we go to float and then go back to double and make sure that the result is the same. If d does not fit into the float, then some precision would be lost when using (float)d , and therefore the result would be different.

Strictly speaking, a return to double not required, since the comparison operator will do this implicitly, therefore (float)d == d is fine too.

If you're worried about the effectiveness of this, because many floating point operations are much slower than comparable int operations: this is pretty much no problem. The conversion between float and double is extremely efficient in modern processors. You can even vectorize it! There are cvtpd2ps and cvtps2pd commands in the SSE2 instruction set that convert from double to float and vice versa (4 values ​​are converted immediately). The instructions contain a 4-cycle delay for all Intel processors that support them. 4 cycles for 4 conversions are very fast.

+5
source

Similar to pouring float numbers back and forth on double and checking equality ( == ), you can also use Double.compare() :

 double d = 2/3.0; // 0 means OK, d fits into float if (Double.compare(d, (float) d) == 0) System.out.println("OK, fits into float."); 

In addition, since comparing float to double will implicitly cast float to double , we can simply write:

 if ((float) d == d) System.out.println("OK, fits into float."); 
+2
source

If you want to find out if your double value matches the range of float MAX and MIN, you cannot use a listing similar to (float)d == d , because d can correspond to float ranges, but it does not have to have the same decimal places after clicks.

In this case, you should compare with Float.MAX_VALUE and Float.MIN_VALUE

 `return d <= Float.MAX_VALUE && d>0 Float.MIN_VALUE`; 
+1
source

Source: https://habr.com/ru/post/976001/


All Articles