您可以Long.MIN_VALUE
和Long.MAX_VALUE
比較吧:
public static boolean fitsLong(double d) {
return d >= Long.MIN_VALUE && d < Long.MAX_VALUE;
}
某種程度上更sofisticated的方法是使用BigDecimal
:
double value = 1234567.9;
long l = BigDecimal.valueOf(value)
.setScale(0, RoundingMode.HALF_EVEN)
.longValueExact(); // 1234568
double value = 99999999999999999999999999999999.9;
long l = BigDecimal.valueOf(value)
.setScale(0, RoundingMode.HALF_EVEN)
.longValueExact(); // ArithmeticException
這樣,您就可以控制如何進行舍入。
您可能會問,爲什麼fitsLong
中存在嚴格的不等式:d < Long.MAX_VALUE
。其實這是因爲Long.MAX_VALUE
本身不能表示爲雙數。當您投下(double)Long.MAX_VALUE
時,double
類型中沒有足夠的精度來表示它,因此選擇的最接近的可表示值爲9223372036854775808.0
(Long_MAX_VALUE+1.0
)。所以它是d <= Long.MAX_VALUE
它會返回true
爲實際上有點大,因爲在這個比較Long.MAX_VALUE
常數提升爲雙重類型的數字。另一方面Long.MIN_VALUE
可以完全代表double
類型,因此我們在這裏有>=
。
而且它們也同樣吸引爲什麼以下工作:
double value = -9223372036854775809.9; // Long.MIN_VALUE-1.9
System.out.println(fitsLong(value)); // returns true
那是因爲你實際上並沒有減去從Long.MIN_VALUE
什麼。請參閱:
double d1 = Long.MIN_VALUE;
double d2 = -9223372036854775809.9;
System.out.println(d1 == d2); // true
雙精度不夠-9223372036854775808
和-9223372036854775809.9
區分,所以它實際上是相同的雙號。在編譯期間它被轉換成二進制形式,而這兩個數字的二進制形式是相同的。因此在編譯程序時,您無法區分-9223372036854775808
或-9223372036854775809.9
是否在源代碼中。
如果你覺得它仍然是問題,從String
構建BigDecimal
:
long l = new BigDecimal("-9223372036854775808.2")
.setScale(0, RoundingMode.HALF_EVEN)
.longValueExact(); // ok, -9223372036854775808
long l = new BigDecimal("-9223372036854775808.9")
.setScale(0, RoundingMode.HALF_EVEN)
.longValueExact(); // ArithmeticException
對於第一種解決方案)其實你不能。我試過了,它不會工作。例如嘗試一個值9223372036854775809.9,將Long.MAX_VALUE增加2.9。會過去的。 – arenaq
你是對的,但當我使用9223372036854775807.0這兩種解決方案。 FitsLong讓我真實,BigDecimal拋出一個異常。這個雙重價值可能會保持不變,但至少有一個解決方案必須是錯誤的。 – arenaq
@arenaq double有53位尾數,只能精確到15-17位。有沒有辦法區分9223372036854775809.9和9223372036854775807 http://stackoverflow.com/q/588004/995714 –