【问题标题】:Converting double value of 1234567.1234 to float in java在java中将1234567.1234的double值转换为float
【发布时间】:2015-08-27 19:04:42
【问题描述】:

我正在尝试在 java 中将 double 转换为 float。

Double d = 1234567.1234;
Float f = d.floatValue();

我看到f的值为

1234567.1

我不想打印一个浮点数的字符串值。我只是想知道在将 double 转换为 float 时不会丢失任何精度的最大位数是多少。我可以在 java 中显示超过 8 个有效数字吗?

【问题讨论】:

  • @Tunaki 我不想打印字符串,我在调试时看到了 float 的值。编辑了问题。
  • “不丢失任何精度的最大位数”是什么意思?您问题中 Float 值的实际值为 1234567.125。
  • @RealSkeptic 我只想在转换为浮点数时获得相同的双精度值。我的意思是最大位数是多少?
  • 并非所有双精度值都可以精确地表示为浮点值。这实际上是 double 存在的全部原因:提供比 float 更高的精度(即更多可用的数字)。此外,“[十进制] 位数”是考虑浮点数的一种过于简单化(因此注定要失败)的方式。

标签: java floating-point double floating-point-precision


【解决方案1】:

float32 位(4 字节),其中 23 位 用于尾数(6 到 9 位十进制数字,平均约 7 个)。 8 位用于指数,因此浮点数可以使用这 8 位将小数点向右或向左“移动”。这样做可以避免在尾数中存储大量零,如 0.0000003 (3 × 10-7) 或 3000000 (3 × 107)。有 1 位用作符号位。

double64 位(8 字节),其中 52 位 用于尾数(15 到 17 位十进制数字,平均约 16 个)。 11位用于指数,1位为符号位。

我相信你达到了这个限制是什么导致了这个问题。

如果你改变了

Double d = 123456789.1234;
Float f = d.floatValue();

您将看到浮点值为 1.23456792E8

【讨论】:

    【解决方案2】:

    float 的精度约为 7 位小数,但由于浮点数以二进制形式存储,因此这是一个近似值。

    为了说明有问题的浮点值的实际精度,试试这个:

    double d = 1234567.1234;
    float f = (float)d;
    System.out.printf("%.9f%n", d);
    System.out.printf("%.9f%n", Math.nextDown(f));
    System.out.printf("%.9f%n", f);
    System.out.printf("%.9f%n", Math.nextUp(f));
    

    输出

    1234567.123400000
    1234567.000000000
    1234567.125000000
    1234567.250000000
    

    如您所见,有效小数精度大约此数字的小数点后 1 位,或 8 位,但如果您使用数字 @987654324 运行代码@,你得到:

    9876543.987600000
    9876543.000000000
    9876544.000000000
    9876545.000000000
    

    这只是 7 位精度。

    【讨论】:

      【解决方案3】:

      这是一个简单的例子,支持没有安全的小数位数的观点。

      考虑 0.1。

      最接近的 IEEE 754 64 位二进制浮点数具有精确值 0.1000000000000000055511151231257827021181583404541015625。它转换为 0.100000001490116119384765625 的 32 位二进制浮点数,与 0.1 相差甚远。

      即使是一个有效数字和一个小数位也可能会丢失精度。

      除非你真的需要float的紧凑性,并且对精度要求非常宽松,否则最好还是坚持double。

      【讨论】:

        【解决方案4】:

        我只是想知道在将 double 转换为 float 时不会丢失任何精度的最大位数是多少。

        也许你没有意识到,但 N 位精度的概念已经很模糊了。毫无疑问,您的意思是“N 位精度以 10 为底”。但与人类不同的是,我们的计算机使用 Base 2。

        不可能在不损失精度的情况下将每个数字从 Base X 转换为 Base Y(保留的数字数量有限),例如1/3rd 的值完美在 Base 3 中准确地表示为“0.1”。在 Base 10 中,它有无限数量的数字 0.3333333333333 ......同样,通常在 Base 10 中可以完美表示的数字,例如0.1 需要无限位数才能以 Base 2 表示。另一方面,0.5(Base 10)完全可以准确地表示为 0.1(Base 2)。

        回到

        我只是想知道在将 double 转换为 float 时不会丢失任何精度的最大位数是多少。

        答案是“取决于价值”。普遍引用的经验法则“浮点数的十进制精度约为 6 到 7 位”只是一个近似值。取决于价值,它可以更多或更少。

        在处理浮点时,相对精度的概念更有用,不要再考虑“数字”,而是用相对误差代替它。任何数字 N(在范围内)都可以用(最多)N / 准确度的误差表示,准确度是所选格式的尾数位数(例如,浮点数为 23(+1),浮点数为 52(+1))双倍的)。因此,表示为浮点数的十进制数的最大近似误差为 N / pow(2, 24)。误差可能更小,甚至为零,但永远不会更大。

        23+1 的约定是浮点数按照选择的指数进行组织,这样第一个尾数位始终为 1(只要可能),因此不需要显式存储。物理存储的位数,例如因此,23 允许一个额外的精度位。 (有一个例外情况,“只要可能”不适用,但我们在这里忽略它)。

        TL;DR:在浮点双精度中没有固定的小数位数精度。

        【讨论】:

          【解决方案5】:

          编辑。
          不,您无法在 Java 中使用浮点数更精确,因为浮点数只能包含 32 位(4 个字节)。如果您想要更高的精度,则继续使用 Double。 This 也可能有帮助

          【讨论】:

          • 没关系……还是一样。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-01-02
          • 1970-01-01
          相关资源
          最近更新 更多