對於下面的代碼(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