【问题标题】:Float in java generating unexpected outputjava中的浮点数产生意外的输出
【发布时间】:2013-09-18 13:31:45
【问题描述】:

我正在编写一个带有浮点数的示例程序,但突然发生了一些奇怪的事情。如果有人能从我的程序中解释为什么我会面临这种行为,我将不胜感激。

package Programs;

public class FloatTest {

    /**
     * @param args
     */
    public static void main(String[] args) {
        float f1 = (float) 3.2;
        float f2 = (float) 6.5;
        if (f1 == 3.2) {
            System.out.println(f1 + " same");
        } else {
            System.out.println(f1 + " different");
        }
        if (f2 == 6.5) {
            System.out.println(f2 + " same");
        } else {
            System.out.println(f2 + " different");
        }
    }
}

输出:

3.2 different
6.5 same

在改变 f2 的值进行一些测试后,我注意到我得到了 f2 > 3.5 的意外结果,这是为什么?任何意见都非常感谢。

谢谢

【问题讨论】:

  • 双双双双双双双双。
  • 因为 6.5 可以用二进制浮点数精确表示,与 3.2 不同。
  • @LeeMeador Java 中的规则是,当转换为浮点数或双精度数时,将数字四舍五入到可以表示的最接近的值,如果等距,则舍入到最低有效位为 0 的值。这适用于文字和转换,因此对于 3.2f,浮点值将是最接近 3.2 的值;对于 (float)3.2,文字 3.2 表示最接近 3.2 的 double,然后强制转换为 float 会导致结果是最接近该 double 的浮点值。这两个通常应该产生相同的浮点数,但应该有一些罕见的极端情况不会。

标签: java


【解决方案1】:

我将尝试对此进行技术解释。由于这些值最终以二进制格式存储,因此在某些情况下会丢失精度。

6.5 不应丢失任何精度,因为它可以转换为二进制值110.1

但是,3.2 不能像这样干净地转换,因为.2 的二进制表示变得不合理。这将类似于11.00110011..。当以另一种方式转换时,这最多只能四舍五入为3.2

如果有人能验证我所说的话,那就太棒了——这是基于对 Java 如何处理这个问题的公认有限知识。

【讨论】:

  • 你在这里有它的要点,所以+1。
  • 干杯 - 据我了解,存储像 3.2 这样的精确值的唯一方法是使用另一个答案中提到的 BigDecimal 类。
  • 确实,尽管在大多数科学数字运算中,双精度就足够了。但是你绝不能使用浮点数来表示金钱。
  • @Bathsheba 你可以用float来代表钱。如果你需要做一些事情,比如计算利息或评估库存,当有些物品的价值低于 1 美分(以美元计)[例如12 个,每个 $1.00 = $.085] 为了使它工作,你和每个接触代码的人都必须非常小心地在所有正确的点上舍入数字,并以正确的顺序进行加法、减法,甚至更多的乘法和除法。跨度>
【解决方案2】:

由于浮点变量的表示方式,并非所有数字都可以精确表示。事实上,很少有人能做到。

当你写作时

float f1 = (float) 3.2;

并将其与 3.2 进行比较,您将f1float)与3.2(作为文字输入的double3.2 隐含为double 类型)进行比较。在您的声明 f1 == 3.2 中,f1 被隐式转换为 double,但到那时,精度已经丢失。这是因为3.2 是无法精确表示的数字之一,而doublefloat 做得更好。

巧合的是,6.5 是可以精确表达的数字之一(doublefloat),这是由于 Java 用于表示浮点的内部方案。这就是为什么在你的情况下,f2 == 6.5true

【讨论】:

    【解决方案3】:

    有很多方法可以解决这个问题,

    出现此问题是因为无法表示十进制值 准确的二进制。

    1. 有一个容差值,检查差值是否小于容差值。
    2. 乘以 10/100/...,然后比较数字
    3. 查看BigDecimal

    然后通过this for sure.

    【讨论】:

    • 对于公差,请使用如下内容:if (Math.abs(3.2f - f1) > 0.05f) ...。当然,我们可以整天争论要与之比较的价值。 0.05 或 0.000001 或其他。对于您的代码,您可能会知道距离足够近。
    【解决方案4】:

    使用演员 if (f1 == (float)3.2) { 然后它会起作用。

    3.2 这样的字面量是双精度类型,而您将浮点数与双精度数进行比较,这会导致此类事情发生。

    正如@JNL 指出的那样

    出现此问题是因为十进制值无法在二进制中准确表示。

    【讨论】:

      【解决方案5】:

      :) Ahh IEEE754 和 JVM 与浮点数的区别。简而言之,6.5 与浮点值 6.5 不同。 6.5 == 6.5f 会起作用,但你更好地理解你在做什么!请阅读http://en.wikipedia.org/wiki/IEEE_floating_point,另请注意“strictfp”关键字以强制跨平台执行 IEEE754 行为。这里有很多事情要考虑,舍入行为、优先顺序、JVM 差异等。不是整数或长整数的事情出乎意料地棘手。

      您正在处理一个数字的二进制表示,该数字的精度适用于不需要无限精确答案的许多类型的数学计算。对于许多工程和金融系统,尤其是那些涉及乘法或分数的系统,这是不可接受的。您要么需要重新计算您的会计基础(使用理解金钱和小数的金融类),(例如用便士计算金钱),并且对于工程,您可能需要使用 BigDecimal 或具有特定舍入行为、精度等的相关类.

      再举一个例子,浮点值 1/3 + 1/3 + 1/3,可能等于也可能不等于 1。因为构成数据的数字表示的 1 和 0 不完全是 1 /3。在我的特定平台(JVM 1.6 Windows 64 位)上,它是 1.0,但它可能不在你的平台上。

      【讨论】:

      • 我很确定 1/3 + 1/3 + 1/3 等于 0。
      • @pamphlet 你能解释一下你的陈述吗? May be this link could help to enlighten your math knowledge.
      • @Smit, 1/3 在 Java 中是整数运算,计算结果为 0。我不确定这个链接是否启发了我,但它确实让我很想吃披萨。
      • @pamphlet LOL 在 Java 整数算术意义上,你是正确的,抱歉链接让你饿了。
      【解决方案6】:

      虽然看起来不正确,但当你运行时

      float f1 = (float) 3.2;
      

      f1 并不等于 3.2。如前所述,有多种方法可以解决此问题。

      【讨论】:

        猜你喜欢
        • 2017-03-19
        • 2019-11-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-07
        • 1970-01-01
        • 2020-09-03
        相关资源
        最近更新 更多