Java 和浮点运算
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
在我最初的 post 中,我没有明确说明我想要什么。 Patricia Shanahan 通过建议 Math.ulp
猜测
尝试"double"键。如果还不够,试试"long double".
虽然值0.00000001f
在float
的精度范围内,但值-180f + 0.00000001f * 2
(-179.99999998
)不. float
只有大约 7-8 位有效数字的精度,而 -179.99999998
至少需要 11 位。所以它的最低有效位被 the addition operation 丢弃,不精确的值最终是-180.0f
.
只是为了好玩,here are those values in bits (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
,那问题 goes away,因为您没有超过 double
的 ~15 位精度。
按照之前答案中的建议,最好的解决方案是使用 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]
有代码
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
在我最初的 post 中,我没有明确说明我想要什么。 Patricia Shanahan 通过建议 Math.ulp
尝试"double"键。如果还不够,试试"long double".
虽然值0.00000001f
在float
的精度范围内,但值-180f + 0.00000001f * 2
(-179.99999998
)不. float
只有大约 7-8 位有效数字的精度,而 -179.99999998
至少需要 11 位。所以它的最低有效位被 the addition operation 丢弃,不精确的值最终是-180.0f
.
只是为了好玩,here are those values in bits (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
,那问题 goes away,因为您没有超过 double
的 ~15 位精度。
按照之前答案中的建议,最好的解决方案是使用 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]