提问人:notwhale 提问时间:9/17/2023 最后编辑:Federico klez Cullocanotwhale 更新时间:9/17/2023 访问量:92
为什么当我使用 Float.MIN_VALUE 参数调用构造函数时,它们是 0?
Why is it that when I call the constructor with Float.MIN_VALUE parameters, they are 0?
问:
所以我有一个带有构造函数的类:Vector3f
public Vector3f(float x, float y, float z) {
this.x = x;
this.y = y;
this.z = z;
}
但是当我像这样调用构造函数时:
Vector3f max = new Vector3f(Float.MIN_VALUE, Float.MIN_VALUE, Float.MIN_VALUE);
并将值打印到控制台:
System.out.printf("x: %f, y: %f, z: %f\n", max.x, max.y, max.z);
输出将是
x: 0.000000, y: 0.000000, z: 0,000000
为什么是 0?
我使用了 Java OpenGL 数学库 (JOML)。Vector3f
答:
您的问题可以用两种完全不同的方式来解读。我可以回答他们俩。
你期望它是一个非常大的负数
那不是做什么的。但是,您的困惑是可以理解的; 是一个非常大的负数。这个概念不适用于浮点数/双精度数,因为它们有一个表示负无穷大的值,这使得“比任何其他数字都更负的数字”意义上的“MIN_VALUE”是可疑的/不存在的。这个名字仍然很不幸,但 java 通常不会在没有比“命名令人困惑”更好的理由的情况下改变事情,以避免向后兼容性问题。MIN_VALUE
Integer.MIN_VALUE
float
Float.MIN_VALUE
表示不等于 0 的最小正可表示浮点数。
我知道那件事。但它打印 0!
float 和 double 的问题在于它们不精确。如果我递给你一张便利贴,让你在上面写十进制的 1/3,你不能。您将写入 0.3333 并最终耗尽空间。 并且或多或少相同,除了二进制,除了十进制,这特别痛苦,因为只有适合 2 的东西才能被准确地表示。我们可以做十进制的 1/10(毕竟是 0.1)。在IEEE数学中,这与1/3一样有问题。几乎所有的分数都是有问题的,除了 1/2、3/4 等(除数是 2 的幂 - 没关系)。double
float
让我们看看它的实际效果:
double v = 0.0;
for (int i = 0; i < 10; i++) v += 0.1;
System.out.println(v == 1.0);
打印...哎呀,这是错误的。 显然是1.0。但显然不是IEEE双数学。就像您在 1/3 处尽最大努力的 3 个帖子的总和不完全是 1.0(它将是 0.9999999),我们在这里遇到了同样的问题。false
10 * 0.1
那么,这如何导致打印 0.0000?
因为数字是以二进制存储的,但以十进制打印,如果打印确切的值,这会导致一些真正的不稳定和意外的行为。你会得到 0.9999999999999999999999876 很多,这很烦人。因此,相反,printf/println 只是在黑暗中疯狂地刺伤并进行一些可疑的四舍五入,以使其看起来都正确,而这一切都不是。println
这就是为什么你永远不应该只打印双精度的原因。相反,像你一样使用/。并指定您想要的位数,以便您可以控制这种必要的舍入。如果没有显式说明符,则默认为 6 位数字。而“最小的非零正浮点数”,四舍五入,适合 6 位数字,是 0.000000。你需要更多的数字才能看到这个微小的数字:printf
String.format
%f
System.out.printf("%.99f\n", Float.MIN_VALUE);
> 0.0000000000000000000000000000000000000000000014012984643248170000000
这就是您需要多少位数才能看到它。
一些重要提示
float
没用。 同样快或更快,在所有 99% 的情况下占用同样多的空间(除了通常小一点,但这是它唯一容易出现的地方),并且不太精确。只是不要使用它 - 相反。double
float[]
double
- 解决这个“不准确”问题的另一种方法是根本不使用浮点数/双精度数。找到一个原子单位并用 int/long 表示原子单位,或使用 BigDecimal。不过,出于 GUI 目的,不准确通常是值得的。
评论
Float.MIN_VALUE
2
-149
1.4E-45
%f
%.45f
%f
MIN_VALUE
Formatter
%f