如何快速检查是否适合浮动? (JAVA)

是否有一些算术或按位运算可以检查双精度是否适合浮点而不会损失精度。

它不仅要检查双范围是否在浮点范围内,还要检查没有尾数位丢失。

再见

PS:这解决了C#中途的问题: 如何在不转换为无穷大的情况下检查双精度是否适合浮点但是我需要一个适用于Java的解决方案。

直接的解决方案可能如下所示:

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

它输出:

 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 

编辑:速度比较显示,方法2似乎最快:

  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 

码:

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

这个怎么样:

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

这个想法非常简单:我们首先转换为float然后再转换为double并检查结果是否仍然相同。 如果d不适合浮点数,则在(float)d转换时会丢失一些精度,因此结果会有所不同。

严格地说,由于比较运算符将隐式执行此转换,因此无需转换为double ,因此(float)d == d也可以。

如果你担心这个的性能,因为许多浮点运算比类似的int操作慢得多:这在这里几乎不是问题。 float和double之间的转换在现代CPU中非常有效。 它甚至可以被矢量化! SSE2指令集中有cvtpd2pscvtps2pd指令,它们执行从double到float的转换,反之亦然(一次转换4个值)。 这些指令在支持它们的所有Intel CPU上具有4个周期的延迟。 4次转换的4个周期非常快。

类似于将数字转换为float并返回double并检查相等性( == ),也可以使用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."); 

此外,由于将floatdouble进行比较会隐式地将floatdouble ,我们可以简单地写:

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

如果你想知道你的double值是否适合浮动的MAX和MIN范围,你就不能使用类似(float)d == d因为d可能适合浮点范围但不必要在转换后具有相同的小数。

在这种情况下,您必须与Float.MAX_VALUEFloat.MIN_VALUE进行比较

 return d <= Float.MAX_VALUE && d >= Float.MIN_VALUE;