是否有一些可以检查的算术或按位运算 是否双重适合浮动没有损失 精确度。
它不应该只检查双倍范围 在浮点范围内,也没有尾数位 迷路了。
再见
P.S。:这解决了C#中途的问题: How to check if a double can fit into a float without conversion to infinity 但我需要一个适用于Java的解决方案。
答案 0 :(得分:6)
直接的解决方案可能如下所示:
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;
}
}
}
答案 1 :(得分:5)
这个怎么样:
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中非常有效。它甚至可以被矢量化! cvtpd2ps
指令集中有cvtps2pd
和SSE2
指令执行从double到float的转换,反之亦然(4个值一次转换)。这些指令在支持它们的所有Intel CPU上具有4个周期的延迟。 4次转换的4个周期非常快。
答案 2 :(得分:2)
与将数字转换为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.");
此外,由于将float
与double
进行比较会隐式地将float
强制转换为double
,我们可以简单地写一下:
if ((float) d == d)
System.out.println("OK, fits into float.");
答案 3 :(得分:1)
如果你想知道你的double值是否适合浮点数的MAX和MIN范围,你就不能使用类似(float)d == d
的强制类型,因为d可能适合浮动范围但不必要在强制转换后具有相同的小数。
相比之下,您必须与Float.MAX_VALUE
和Float.MIN_VALUE
return d <= Float.MAX_VALUE && d >= Float.MIN_VALUE;