从另一个浮点数中减去 Float.MIN_VALUE 在 android 应用程序中没有影响

subtracting Float.MIN_VALUE from another float number has no effect in android application

我正在开发一个 android 应用程序,该应用程序的一部分有 2 个浮点值,我不能让它们完全相同,因为这会导致我的其中一个屏幕出现错误.这些数字是从服务器发送的,不受我的控制(例如,我不能强制它们不同)。

该应用程序是用 Kotlin 编写的,但我认为此问题与 Java 类似(如果不完全相同),因为 Kotlin 在幕后使用 JVM。

我想到了一种“创造性”的方法来解决这个问题,而又不会过多改变我的逻辑,方法是从其中一个中减去 Float.MIN_VALUE,使它们几乎 ,但不完全是 一样。我真正需要做的是 if(a == b) 失败(b 实际上是 a - Float.MIN_VALUE)。

但令我惊讶的是,当代码运行时,if(a == b) returns true。当我在 Android Studio 中打开“评估”window 时,我发现了以下内容:

让我重申一下 currentPayment 是一个 Float,所以不应该进行任何自动转换或舍入(比如将 Float 除以 Int 例如)。

我还要指出,我可以保证 currentPayment 不是 Float.MAX_VALUE-Float.MAX_VALUE(因此运算结果在 Float 的范围内)。

根据文档, Float.MIN_VALUEFloat 的最小正非零值,值为 1.4E-45,此处确认:

我在另一个post中也看到了(不知为何又找不到了),这也可以认为是Float的最大精度,这是有道理的。

因为 currentPayment 是一个 Float,我希望它应该能够在 [=19= 的范围内保存 any 浮点值] 到它的最大精度(即 Float.MIN_VALUE)。 因此我希望 currentPaymentNOT 等于 currentPayment - Float.MIN_VALUE,但事实并非如此。

谁能解释一下?

Since currentPayment is a Float, I would expect it should be able to hold any floating point value within the bounds of Float to it's maximum precision (i.e. Float.MIN_VALUE).

这是一个错误的假设。浮点数之所以称为“float”,是因为它具有浮点精度。精确度取决于您存储的数字有多大。最小可能的浮点值比几乎任何其他可能数字的精度都小,所以如果你加或减它,它太小而不会影响它们。在高端,浮点数的精度比整数 1 大得多。如果从 Float.MAX_VALUE 中减去 999,000,000,它仍然会 return Float.MAX_VALUE 因为精度太差了最高端。

此外,由于浮点数不以 10 为基数存储,因此它们不适合存储货币金额,因为您永远无法准确表示小数。 (我提到是因为你的变量名里面有“payment”这个词,这是一个危险信号。)

您应该使用 BigDecimal、Long 或 Int 来表示货币,这样您的货币数量和算法将是准确的。


编辑: 这是一个有助于理解它的类比,因为很难考虑二进制数。在 Java 和 Kotlin 中,浮点数是 32 位的,但想象一下我们有一种特殊的计算机可以以 10 进制存储浮点数。这台电脑上的每一位不只是0或1,而是可以是0到9之间的任何值。这台电脑上的Float可以有4位数字和一个小数位,但小数位是浮动的,所以它可以放在相对于四位数。所以这台计算机上的 Float 总是五位——其中四位是数字,第五位告诉你小数点的位置。

在这个假想的计算机的Float中,可以表示的最小可能数是.0001,最大可能数是9999.。您不能表示 9999.5 甚至 1000.5,因为没有足够的可用数字。没有固定的精度——精度取决于当前数字中小数点的位置。小数点位置越靠左的数字精度越高。

为了使数字存储格式能够具有固定精度,我们必须将所有数字的小数点固定在一个位置。我们将不得不选择一个精度。假设我们选择了 0.001 的精度。我们的第五位告诉我们小数点在浮点数中的位置,现在可以只用于第五位数字。现在我们知道精度是always0.001,但是我们能表示的最大可能数是99.999,最小可能数是0.001,a可能的范围比浮点小得多。此限制是使用浮点数的原因。