[英]How quickly check whether double fits in float? (Java)
Are there some arithmetic or bitwise operations that can check whether a double fits into a float without loss of precision.是否有一些算术或按位运算可以检查双精度是否适合浮点数而不会损失精度。
It should not only check that the double range is in the float range, but also that no mantissa bits get lost.它不仅应该检查双精度范围是否在浮点范围内,还要检查尾数位是否丢失。
Bye再见
PS: This answers the problem half way for C#: How to check if a double can fit into a float without conversion to infinity But I need a solution that works for Java. PS:这回答了 C# 的一半问题: How to check if a double can fit into a float without conversion to infinity但我需要一个适用于 Java 的解决方案。
How about this:这个怎么样:
double d = ...;
if ((double)(float)d == d) {
System.out.println(d + " fits into float!");
}
The idea is pretty simple: We first cast to float
and then back to double
and check whether the result is still the same.这个想法很简单:我们首先转换为
float
然后返回double
并检查结果是否仍然相同。 If d
does not fit into float, then some precision would have been lost at the (float)d
cast and thus the result would be different.如果
d
不适合 float,那么在(float)d
转换时会丢失一些精度,因此结果会有所不同。
Strictly speaking, the cast back to double
is not necessary as the comparision operator will do this cast implicitly, so (float)d == d
is also fine.严格来说,转换回
double
是不必要的,因为比较运算符会隐式执行此转换,因此(float)d == d
也可以。
If you are worried about the performance of this, because many float operations are a lot slower than comparable int operations: This is pretty much a non-issue here.如果您担心它的性能,因为许多浮点操作比可比较的 int 操作慢得多:这在这里几乎不是问题。 Conversion between float and double is extremely efficient in modern CPUs.
在现代 CPU 中,float 和 double 之间的转换非常有效。 It can even be vectorized!
它甚至可以被矢量化! There are the
cvtpd2ps
and cvtps2pd
instructions in the SSE2
instruction set that perform the conversion from double to float and vice versa (4 values are converted at once). SSE2
指令集中有cvtpd2ps
和cvtps2pd
指令,它们执行双浮点数和浮点数之间的转换(一次转换 4 个值)。 The instructions have a latency of 4 cycles on all Intel CPUs that support them.这些指令在支持它们的所有 Intel CPU 上都有 4 个周期的延迟。 4 cycles for 4 conversions is extremely fast.
4 次转换的 4 个周期非常快。
A straight-forward solution could 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"));
}
}
}
it outputs:它输出:
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, that method2 seems to be fastest:编辑:速度比较显示,method2 似乎最快:
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;
}
}
}
Similarly to casting the number to float
and back to double
and checking for equality ( ==
), Double.compare()
can also be used:类似于将数字转换为
float
并返回到double
float
数并检查相等性 ( ==
),也可以使用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.");
Moreover, since comparing a float
to double
will implicitly cast the float
to double
, we can simply write:此外,由于比较一
float
至double
将隐式转换的float
至double
,我们可以简单的写:
if ((float) d == d)
System.out.println("OK, fits into float.");
If you want to know if your double value fits the MAX and MIN range of float yout can´t use cast like (float)d == d
because d may fits the float ranges but not necessary has the same decimals after cast.如果您想知道您的 double 值是否适合浮点数的 MAX 和 MIN 范围,则不能使用
(float)d == d
类的强制转换,因为 d 可能适合浮点数范围,但在强制转换后不必具有相同的小数。
In than case you must compare with Float.MAX_VALUE
and Float.MIN_VALUE
在这种情况下,您必须与
Float.MAX_VALUE
和Float.MIN_VALUE
进行比较
return d <= Float.MAX_VALUE && d >= Float.MIN_VALUE;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.