以下是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代码:
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
int i = (int) (d * n); i == m;
对于m=1,n=49,这是错误的。
i = (int) Math.round(d * n); i == m;
我的直觉告诉我应该是正确的,但严格证明可能很困难。
javascript: 1 / 49 * 49
,这将得到0.9999...。 - Nayukidouble
具有 53 位精度,而且您将其除以和乘以小于 2^31
的数,结果的偏差应该小于 1/2^21 = 2 * 1/2^22
(因为进行了两个操作,所以乘以 2)。 因此,舍入将具有很大的整数精度。 - starblue1 /(n)
,则舍入乘法将无法恢复原始的除以int。通常,较大的ulp与较大的double值相关联。与double关联的ulp在约9E15处开始超过1; 如果您恢复的double值在那里左右,那么您可能会发现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");
}
将其四舍五入使用Math.round,然后转换为int应该可以恢复原始int值。int 1073741823 最多会导致4.768371577590358E-7的误差
从数学上讲,这应该是正确的。然而,由于浮点数舍入误差,它可能会变成错误的。你几乎永远不应该使用==
来比较浮点精度数字。
最好使用类似这样的阈值进行比较:
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。