【问题标题】:Convert float to double without losing precision将 float 转换为 double 而不会丢失精度
【发布时间】:2010-10-29 07:13:41
【问题描述】:

我有一个原始浮点数,我需要一个原始双精度数。简单地将浮点数转换为 double 会给我带来奇怪的额外精度。例如:

float temp = 14009.35F;
System.out.println(Float.toString(temp)); // Prints 14009.35
System.out.println(Double.toString((double)temp)); // Prints 14009.349609375

但是,如果我不进行强制转换,而是将浮点数输出为字符串,并将字符串解析为双精度字符串,我会得到我想要的:

System.out.println(Double.toString(Double.parseDouble(Float.toString(temp))));
// Prints 14009.35

有没有更好的方法而不是转到 String 并返回?

【问题讨论】:

    标签: java floating-point double


    【解决方案1】:

    这并不是说您实际上获得了额外的精度 - 而是浮点数没有准确地表示您最初瞄准的数字。 double is 准确地代表了原来的浮点数; toString 正在显示已经存在的“额外”数据。

    例如(这些数字不正确,我只是在编造)假设你有:

    float f = 0.1F;
    double d = f;
    

    那么f 的值可能正好是 0.100000234523。 d 将具有完全相同的值,但是当您将其转换为字符串时,它会“相信”它的精确度更高,因此不会提前四舍五入,您会看到“额外的数字”它们已经在那里,但对你隐藏了。

    当您转换为字符串并返回时,您最终会得到一个比原始浮点数更接近字符串值的双精度值 - 但这只有 如果 你真的相信字符串值是您真正想要的。

    您确定 float/double 是在此处使用而不是 BigDecimal 的合适类型吗?如果您尝试使用具有精确十进制值的数字(例如货币),那么 BigDecimal 是更合适的 IMO 类型。

    【讨论】:

      【解决方案2】:

      我发现转换为二进制表示更容易解决这个问题。

      float f = 0.27f;
      double d2 = (double) f;
      double d3 = 0.27d;
      
      System.out.println(Integer.toBinaryString(Float.floatToRawIntBits(f)));
      System.out.println(Long.toBinaryString(Double.doubleToRawLongBits(d2)));
      System.out.println(Long.toBinaryString(Double.doubleToRawLongBits(d3)));
      

      您可以看到通过在末尾添加 0 将浮点数扩展为双精度,但 0.27 的双精度表示“更准确”,因此出现了问题。

         111110100010100011110101110001
      11111111010001010001111010111000100000000000000000000000000000
      11111111010001010001111010111000010100011110101110000101001000
      

      【讨论】:

        【解决方案3】:

        这是由于Float.toString(float),的合同部分内容:

        必须打印多少位数 小数部分 […]?那里 必须至少为一位数字 表示小数部分,并且 除此之外,还有很多,但只有一样多, 唯一需要的更多数字 区分参数值 浮点类型的相邻值。 是,假设 x 是精确的 表示的数学值 由产生的十进制表示 此方法用于有限非零 论据 f。那么 f 必须是浮点数 最接近 x 的值;或者,如果两个浮动 值同样接近 x,然后 f 必须是其中之一,也是最少的 有效位的有效位 f 必须为 0。

        【讨论】:

          【解决方案4】:

          我今天遇到了这个问题,无法使用重构到 BigDecimal,因为这个项目真的很大。但是我使用

          找到了解决方案
          Float result = new Float(5623.23)
          Double doubleResult = new FloatingDecimal(result.floatValue()).doubleValue()
          

          这行得通。

          注意调用 result.doubleValue() 返回 5623.22998046875

          但调用 doubleResult.doubleValue() 正确返回 5623.23

          但我不完全确定它是否是正确的解决方案。

          【讨论】:

          • 为我工作。也非常快。不知道为什么这没有被标记为答案。
          • 这是我使用的方法,你不需要新的 Float 部分......只需使用原语创建 FloatingDecimal。它将被自动装箱...而且工作速度也很快...有一个缺点,FloatingDecimal 是不可变的,因此您需要为每个浮点数创建一个...想象一下 O(1e10) 的计算代码! !!当然 BigDecimal 也有同样的缺点……
          • 这个解决方案的缺点是 sun.misc.FloatingDecimal 是 JVM 的内部类,并且在 Java 1.8 中其构造函数的签名已更改。任何人都不应该在现实生活中使用内部类。
          【解决方案5】:

          我找到了以下解决方案:

          public static Double getFloatAsDouble(Float fValue) {
              return Double.valueOf(fValue.toString());
          }
          

          如果您使用 floatdouble 而不是 FloatDouble,请使用以下内容:

          public static double getFloatAsDouble(float value) {
              return Double.valueOf(Float.valueOf(value).toString()).doubleValue();
          }
          

          【讨论】:

            【解决方案6】:

            使用BigDecimal 而不是float/double。有很多数字不能表示为二进制浮点数(例如,0.1)。因此,您要么必须始终将结果四舍五入到已知精度,要么使用BigDecimal

            更多信息请参见http://en.wikipedia.org/wiki/Floating_point

            【讨论】:

            • 假设您的缓存中有 1000 万个浮动交易价格,您是否仍然考虑使用 BigDecimal 并实例化唯一的,比如说约 600 万个对象(以折扣享元/不可变).. 或者还有更多?
            • @Sendi_t 请不要使用 cmets 提出复杂的问题 :-)
            • 感谢您的关注!.. 我们现在使用浮动,因为这是十年前商定的——我试图在跟进时了解您对这种情况的看法——。谢谢!
            • @Sendi_t 误会。我无法用 512 个字符回答您的问题。请提出一个正确的问题并给我一个链接。
            • @GKFX 在计算机上处​​理小数时没有“一刀切”。但由于大多数人不明白,我将他们指向BigDecimal,因为这将捕获大多数常见错误。如果事情太慢,他们需要学习更多并找到优化问题的方法。过早的优化是万恶之源 - D.E.克努特。
            【解决方案7】:

            浮点数本质上是不精确的,并且总是有整齐的四舍五入“问题”。如果精度很重要,那么您可以考虑重构您的应用程序以使用 Decimal 或 BigDecimal。

            是的,由于处理器支持,浮点数的计算速度比小数更快。但是,您想要快速还是准确?

            【讨论】:

            • 十进制算术也是不精确的。 (例如 1 / 3 * 3 == 0.9999999999999999999999999999)当然,它更适合表示精确的十进制数量,例如金钱,但对于物理测量,它没有优势。
            • 但是 1 == 0.9999999999999999999999999999 :)
            【解决方案8】:

            有关信息,请参阅 Joshua Bloch 的 Effective Java 第 2 版的第 48 条 - 当需要精确值时避免使用浮点数和双精度数。这本书塞满了好东西,绝对值得一看。

            【讨论】:

              【解决方案9】:

              这行得通吗?

              float flt = 145.664454;
              
              Double dbl = 0.0;
              dbl += flt;
              

              【讨论】:

                【解决方案10】:

                一个行之有效的简单解决方案是从浮点数的字符串表示中解析双精度:

                double val = Double.valueOf(String.valueOf(yourFloat));
                

                效率不高,但很管用!

                【讨论】:

                  猜你喜欢
                  • 2016-06-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2012-10-26
                  • 1970-01-01
                  • 1970-01-01
                  • 2023-03-18
                  • 2013-12-31
                  • 2019-06-01
                  相关资源
                  最近更新 更多