对于下面的代码(JAVA):Java中如何将double转换为int?
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):Java中如何将double转换为int?
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
第二个问题,你问的关注如何ulp大是Java。
如果ULP超过1/(n)
,然后舍入乘法不会恢复原始分INT。通常,较大的ulps与较大的double值相关联。与double相关的ulp在9E15附近开始超过1;如果你的恢复双打在那里,那么你可能会发现问题与轮()没有得到预期的答案。但是,在使用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。
在数学上它应该是正确的。但是,您可能会得到浮点舍入错误,这会使其失败。您几乎不应该使用==
来比较浮点精度数字。
你好得多使用这样的门槛比较它们:
Math.abs(d*n - m) < 0.000001;
注意这两种说法应该是等价的
i = (int) (d * n);
i = (int) Math.round(d * n);
但是例如,如果d=3/2
和n=2
,浮动可能会导致i=2.999999999999
点误差,这在截去后/舍入为2
你对截断的推理很好。但是你的例子很糟糕,因为浮点除以2总是精确的(除了下溢)。 ;-) – Nayuki
第一上是d无限期地不总是真实的。第二个我会说是的,这是真的,但只是因为我想不出一个反例。
如果n是非常大的,它可能是假的,我不知道真的。我知道至少有99%的时间会是真的。
int i = (int) (d * n); i == m;
这是对于m = 1为假,N = 49。
i = (int) Math.round(d * n); i == m;
我的直觉告诉我,它应该是真实的,但它可能是难以严格证明。
不是一个愚蠢的问题;这个问题引发了一些关于浮点算法和整数“可恢复性”的微妙问题。 – Nayuki
最近这个网站上有很多浮点问题 - 嗯... – 2011-08-10 17:56:23