【问题标题】:How does conversion from double to int work in Java?在 Java 中从 double 到 int 的转换是如何工作的?
【发布时间】:2011-10-24 07:50:06
【问题描述】:

对于以下代码(Java):

double d = (double) m / n; //m and n are integers, n>0
int i = (int) (d * n);

i == m

最后一个表达式是否总是正确的? 如果不是这样,这总是正确的吗?:

i = (int) Math.round(d * n);

i == m

【问题讨论】:

  • 不是一个愚蠢的问题;这个问题提出了一些关于浮点运算和整数“可恢复性”的微妙问题。
  • 这个网站最近有很多浮点问题 - 嗯...

标签: java floating-point double int rounding


【解决方案1】:

int i = (int) (d * n); i == m;

对于 m=1,n=49,这是错误的。

i = (int) Math.round(d * n); i == m;

我的直觉告诉我这应该是真的,但可能很难严格证明。

【讨论】:

  • 您甚至可以在 JavaScript 中验证我的陈述。您可以在浏览器中输入:javascript: 1 / 49 * 49,即为 0.9999...。
  • +1 由于double 具有 53 位精度,并且您将其除以小于 2^31,因此结果应该小于 1/2^21 = 2 * 1/2^22(因子 2 来自做两个操作)。所以四舍五入将是一个很大的整数。
  • 我删除了我的帖子,因为我认为我对第二个案例有误,很好的答案(我已经给了你我的 +1)
【解决方案2】:

您提出的第二个问题是关于 ulp 在 Java 中的大小。

如果 ulp 超过 1/(n),则乘法四舍五入将无法恢复原始除法整数。通常,较大的 ulp 与较大的双精度值相关联。与双精度相关的 ulp 在 9E15 左右开始超过 1;如果您恢复的双打就在那里,那么您可能会发现 round() 没有得到预期答案的问题。但是,当您使用 int 值时,除法分子的最大值将是 Integer.MAX_VALUE

以下程序测试 n 的所有正整数值,以查看在尝试恢复已划分的 int 时哪一个导致舍入错误的可能性最大:

  public static void main(String[] args)
  {
    // start with large number
    int m = Integer.MAX_VALUE;
    double d = 0;

    double largestError = 0;
    int bigErrorCause = -1;
    for (int n = 1; n < Integer.MAX_VALUE; n++)
    {
      d = (double) m / n;
      double possibleError = Math.ulp(d) * n;
      if (possibleError > largestError)
      {
        largestError = possibleError;
        bigErrorCause = n;
      }
    }
    System.out.println("int " + bigErrorCause + " causes at most "
        + largestError + " error");
  }

输出是:

int 1073741823 最多导致 4.768371577590358E-7 错误

使用 Math.round 进行四舍五入,然后转换为 int 应该可以恢复原始 int。

【讨论】:

    【解决方案3】:

    在数学上应该是正确的。但是,您可能会遇到浮点舍入错误,从而使其错误。您几乎不应该使用 == 比较浮点精度数。

    你最好使用这样的阈值来比较它们:

    Math.abs( d*n - m ) < 0.000001;
    

    注意这两个语句应该是等价的

    i = (int) (d * n);
    i = (int) Math.round(d * n);
    

    但是,例如,如果 d=3/2n=2,浮点错误可能会导致 i=2.999999999999 在截断/舍入后为 2。

    【讨论】:

    • 你关于截断的推理是好的。但是您的示例很糟糕,因为浮点除以 2 总是准确的(下溢除外)。 ;-)
    【解决方案4】:

    第一个绝对不总是正确的。第二个我会说是的,这是真的,但只是因为我想不出一个反例。

    如果 n 非常大,它可能是假的,我不确定。不过,我知道至少 99% 的情况都是如此。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-02-03
      • 1970-01-01
      • 2013-05-31
      • 1970-01-01
      • 1970-01-01
      • 2013-11-23
      • 2011-09-14
      相关资源
      最近更新 更多