[英]Java and floating point arithmetic
有代码
public static final float epsilon = 0.00000001f;
public static final float a [] = {
-180.0f,
-180.0f + epsilon * 2,
-epsilon * 2
}
a
初始化如下:
[-180.0, -180.0, -2.0E-8]
而不是想要
[-180.0, X, Y]
如何调整epsilon
以达到预期的结果? ——
1)我希望float
而不是double
与之前编写的代码保持一致
2)我不想要-179.99999998
或X
任何其他特定数字,我想要X > -180.0
但X
尽可能接近-180.0
3)我希望Y
尽可能接近0
,但要float
4) 我想要-180.0 < X < Y
在我最初的帖子中,我没有具体说明我想要什么。 Patricia Shanahan 通过建议Math.ulp
猜到了这Math.ulp
正如先前答案中所建议的那样,最好的解决方案是使用double
。 但是,如果要使用float
,则需要考虑其在感兴趣区域中的可用精度。 该程序将您的文字epsilon
替换为与 180f 的最低有效位相关联的值:
import java.util.Arrays;
public class Test {
public static final float epsilon = Math.ulp(-180f);
public static final float a [] = {
-180.0f,
-180.0f + epsilon * 2,
-epsilon * 2
};
public static void main(String[] args) {
System.out.println(Arrays.toString(a));
}
}
输出:
[-180.0, -179.99997, -3.0517578E-5]
尽管值0.00000001f
在float
的精度范围内,但值-180f + 0.00000001f * 2
( -179.99999998
)不在。 float
只有大约 7-8 个有效位的精度,而-179.99999998
至少需要 11 个。所以它的最低有效位被加法运算丢弃,不精确的值最终是-180.0f
。
只是为了好玩,这里是那些以位为单位的值( n
= -180.0f
):
sign | exponent significand - -------- ----------------------- epsilon = 0 01100100 01010111100110001110111 epsilon2 = 0 01100101 01010111100110001110111 n = 1 10000110 01101000000000000000000 result = 1 10000110 01101000000000000000000
结果最终与原始-180.0f
逐位相同。
如果您使用double
,该问题就会消失,因为您没有超过double
的~15 位精度。
尝试“双”键。 如果这对您来说还不够,请尝试“long double”。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.