[英]How does conversion from double to int work in Java?
對於以下代碼(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;
我的直覺告訴我這應該是真的,但可能很難嚴格證明。
您提出的第二個問題涉及 Java 中的ulp有多大。
如果 ulp 超過1/(n)
,則乘法四舍五入將不會恢復原始除法整數。 通常,較大的 ulp 與較大的雙精度值相關聯。 與雙精度相關的 ulp 在 9E15 左右開始超過 1; 如果您恢復的雙打就在那里,那么您可能會發現 round() 沒有得到預期答案的問題。 但是,當您使用 int 值時,除法分子的最大值將是Integer.MAX_VALUE
。
以下程序測試n
的所有正 integer 值,以查看在嘗試恢復已划分的 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");
}
output 是:
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。
第一個絕對不總是正確的。 第二個我會說是的,這是真的,但只是因為我想不出一個反例。
如果 n 非常大,它可能是錯誤的,我不確定。 我知道這至少在 99% 的情況下都是正確的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.