我有一个遗留项目,它有使用float和长变量的数学运算:
long i = initWihtVeryBigNumber();
float multiplier = 1.3f;
i *= multiplier;
这基本上会导致浮动大小导致的圆误差,这必须替换为:
i = (long)( i* (double)multiplier );
或乘数本身应该是double而不是float。
所以问题是如果我将整个项目浮动改为加倍可能导致任何不可预测的行为?如果是这样,你能提供任何可能产生问题的例子吗?
答案 0 :(得分:3)
所以问题是如果我将整个项目浮动改为加倍可能导致任何不可预测的行为?如果是这样,你能提供任何可能产生问题的例子吗?
是。只要方法需要(float)
,将(double)
更改为float
可能会导致问题。例如,
Float.toString((double) 1.0f);
编译错误。
修改强>
我对运行时错误感兴趣,而不是编译错误。
好。您有一个第三方库,它返回List<Float>
(因此下面的testIt()
来自第三方)。如果您盲目地将元素从List
转换为Float
,则会出现运行时错误。
public static List<Float> testIt() {
List<Float> al = new ArrayList<Float>();
al.add(1.0f);
return al;
}
public static void main(String[] args) {
List<?> al = testIt();
for (int i = 0; i < al.size(); i++) {
Object o = al.get(i);
Double v = (Double) o;
System.out.println(v);
}
}
答案 1 :(得分:2)
另一个区别是,与float
不同,对非易失性double
字段的写入不保证是原子的。
这种情况不太可能仅影响尚未正确同步的多线程系统,但男孩会导致意外的运行时问题。
答案 2 :(得分:1)
请注意,即使您将浮动更改为双打,您仍将会出现舍入错误。示例:假设我们将i
设置为3703816849309525656(= 3 * 0x1122334455667788
,这只是我作为实验尝试过的数字。)
long i = 3703816849309525656L;
float multiplier = 1.3f;
i *= multiplier;
System.out.println(i);
输出
4814961529147359232
long i = 3703816849309525656L;
double multiplier = 1.3;
i *= multiplier;
System.out.println(i);
输出
4814961904102383616
但是使用计算器程序(GNU bc
):
(3703816849309525656 * 13) / 10
4814961904102383352.8
因此使用double
可以让您更接近,但结果仍然不正确;当人们处理整数时,人们通常会得到确切的结果。因此,我会考虑使用BigInteger
或BigDecimal
,但我意识到更改需要付出更多努力。