2011-05-03 100 views
15

所以我知道IEEE 754爲非實數值指定了一些特殊的浮點值。在Java中,將這些值轉換爲原始的int確實而不是拋出異常,就像我期望的那樣。相反,我們有以下幾點:爲什麼將Double.NaN轉換爲int不會在Java中引發異常?

int n; 
n = (int)Double.NaN; // n == 0 
n = (int)Double.POSITIVE_INFINITY; // n == Integer.MAX_VALUE 
n = (int)Double.NEGATIVE_INFINITY; // n == Integer.MIN_VALUE 

什麼是在這些情況下拋出異常的原理是什麼?這是一個IEEE標準,還是僅僅是Java設計者的選擇?如果我不知道這樣的演員是否可以例外,會不會有不好的後果?

回答

8

在這些情況下不拋出異常的基本原理是什麼?

我想象的原因包括:

  • 這些都是極端情況,並有可能在做這種事情的應用程序很少發生。

  • 該行爲並非「完全意外」。

  • 當應用程序從double轉換爲int時,預計會出現重大信息丟失。應用程序要麼會忽略這種可能性,要麼演員會在檢查之前加以防範......這也可以檢查這些情況。

  • 沒有其他的double/float操作會導致異常,並且(IMO)在這種情況下執行它會有點兒精神分裂。

這是一個IEEE標準,或者是它只是被Java的設計者選擇呢?

後者,我想。

有沒有不好的後果,我不知道這樣的演員是否可以例外?

無除了顯而易見的...

(但它不是真正相關。在JLS和JVM規範,說他們在說什麼,並改變它們是容易打破現有的代碼。它不只是我們現在正在談論的Java代碼...)


我已經做了一些挖掘。許多可用於從double轉換爲整數的x86指令似乎都會產生硬件中斷......除非被屏蔽。目前尚不清楚指定的Java行爲是否比OP提出的替代方案更容易或更難實現。

+1

我懷疑的決定,沒有轉換拋出一個異常是由強烈的慾望驅使,以避免拋出異常以任何理由,怕迫使代碼中加入它是一個「拋出」條款。然而,從實際的角度來看,如果代碼嘗試將浮點數轉換爲整數並且不適合,代碼不太可能正常工作,因此異常可能比僞造數據更好。 – supercat 2014-02-12 00:22:09

2

事實上,我認爲在某些演員陣容中已經完成了一些操作(可能是針對perf的問題?),以便您可以有一些意外的行爲。看看當您使用>>和< <運營商時會發生什麼。

對於爲例:

public static void main(String[] args) { 
    short test1 = (short)Integer.MAX_VALUE; 
    System.out.println(test1); 
    short test2 = (short)Integer.MAX_VALUE-1; 
    System.out.println(test2); 
    short test3 = (short)Integer.MAX_VALUE-2; 
    System.out.println(test3); 
    short test4 = (short)Double.MAX_VALUE-3; 
    System.out.println(test4); 
} 

將輸出:

-1 
-2 
-3 
-4 
7

什麼是在這種情況下不扔 例外的理由?這是一個 IEEE標準,還是僅僅是由Java的設計者選擇的 ?

IEEE 754-1985標準下的部分將NaN 2.2.1 20和21和2.2.2頁無限清楚地解釋了爲什麼標準所要求的NAN和無限價值的原因。所以這不是Java的事情。

Java Virtual Machine Specification3.8.1 Floating Point Arithmetic and IEEE 754指出,當轉換爲整數類型時,JVM將向零舍入,這將解釋您看到的結果。

該標準確實提到了一個名爲「陷阱處理程序」的功能,可用於確定何時發生溢出或NAN,但Java虛擬機規範明確指出這不是針對Java實現的。它說,在第3.8.1:

的 Java虛擬機的浮點運算不會拋出異常 ,陷阱,或否則爲零信號 無效操作,除法的IEEE 754特殊條件, 溢出,下溢或不準確。 Java虛擬機沒有信號傳遞 NaN值。

因此,不管後果如何,行爲不是未指定的。

是我 不知道如果例外是 用這樣的石膏有不好的後果?

理解標準中陳述的原因應該足以回答這個問題。該標準用詳盡的例子解釋了你在這裏要求的結果。我會發布它們,但這將是太多的信息,並且這些示例可能無法在此版本工具中適當地進行格式化。

編輯

我讀Java Virtual Machine Specification的最新維護審查由JCP最近出版作爲其工作的一部分,對JSR 924並在部分2.11.14命名類型轉換istructions包含一些更多的信息可以幫助你尋找答案,而不是你在找什麼,但我相信它有一點幫助。它說:

在 浮點值的到一個組成 類型T,其中T是int或長變窄數字轉換, 浮點值轉換 如下:

  • 如果浮點值是NaN,則轉換的結果是一個
    int或長0
  • 否則,如果浮點值不是無限大,則
    浮點值四捨五入爲
    整數值V使用IEEE 754
    向零模式回合。

有兩種情況:

  • 如果T是長且該整數的值可以被表示爲一個長期的,然後
    結果是長值V.
  • 如果T是int類型和該整數值可表示爲 一個int,則結果是整型 值V.

否則:

  • 要麼值必須是太小, (大 量值或負無窮大的負值),其結果是int類型或 長的最小 表示值。
  • 還是值必須是太大了,結果
    (幅度大或
    正無窮大的正值)是 類型爲int或長最大可表示值。

從 甲縮小數字轉換雙浮動的行爲根據用 IEEE 754的結果是正確 使用IEEE 754輪 最接近的模式圓形。一個值太小,不能被 表示爲浮點數,將被轉換爲 類型爲 float的正數或負數零;一個值太大而不能被表示爲浮動的 轉換爲 正或負的無窮大。 A 雙NaN總是被轉換爲 浮點NaN。

儘管精度 溢出, 下溢,或損失可能發生,縮小之間 數字類型的轉換從未引起 Java虛擬機拋出 運行時異常的事實(不要混淆 與IEEE 754浮點數 例外)。

我知道這只是重申你已經知道的內容,但它有一條線索,看起來IEEE標準有一個要舍入到最近的要求。也許你可以找到這種行爲的原因。

編輯

IEEE標準在第2.3.2節舍入模式的國家的問題:

通過 默認情況下,圓整裝置向周圍的 最近 。該標準要求提供三種其他的圓整模式;即朝向 0,向+無窮大旋轉並朝向-Infinity。

與轉換爲整數操作一起使用時,向-Infinity舍入會導致轉換成爲落地函數,而向+ Infinity舍入則爲上限。

模式舍入影響溢出,因爲當輪朝向O或圓形朝向 無窮大是有效的,積極的數量級的溢出導致的默認結果是最大的表示數,而不是正無窮。

類似地,當向+無窮或朝向O周圍有效時,負數的上溢將產生最大的負數。

然後他們繼續提到一個爲什麼這在間隔算術中很有用的例子。不能確定,這是你正在尋找的答案,但它可以豐富你的搜索。

+1

看起來你正指向IEEE標準來證明NaN和無窮的存在。我絕對不會質疑這些值應該是IEEE標準或Java的一部分,所以我不確定你爲什麼指出這一點。另外,「趨近於零」不會自動解釋該決定;這種舍入在數學上沒有很好的定義。考慮到決定圍繞*某事*這些是明智的選擇,但決定不得而知。 – 2011-05-04 04:50:42

+0

@Michael McGowan我想我錯了你的問題。我曾認爲它與Java中爲什麼浮點運算不會拋出異常的事實有關。現在我明白你的意思了,爲什麼向下轉換浮點特殊值不會引發算術異常。我想你的問題也適用於「爲什麼整數數據類型不會在溢出或下溢時拋出異常?」因爲事情是Java整型數據類型在面對除零時纔會拋出異常。我也不知道這些設計選擇的原因。對不起,誤會。 – 2011-05-04 12:38:42

+0

@Michael McGowan雖然你已經接受了一個答案,但出於好奇,我決定多讀些關於這個主題的文章,並且發現了其他一些你可能會覺得有用的參考資料。我編輯了我的答案以包含它們。也許這可以幫助你尋求更多的細節。但是,我相信這不是你要找的答案。 – 2011-05-07 14:54:18

1

從1998年開始有一個ACM演示文稿,這個演示文稿目前仍然令人驚訝,並帶來了一些亮點:https://people.eecs.berkeley.edu/~wkahan/JAVAhurt.pdf

更具體地說,關於投射NaN和infinities時出人意料地缺乏例外:請參閱第3頁第3點:「Infinities和NaN在沒有IEEE標準754/854規定的浮點陷阱和標誌保護的情況下釋放,聲稱魯棒性。「

該演示文稿並未真正回答「爲什麼」,但確實解釋了Java語言的浮點實現中有問題的設計決策的後果,並將它們放入了IEEE標準甚至其他實現的上下文中。

0

Java在這方面被打破,但修復它可能會破壞現有的代碼。

試圖通過深入研究IEEE或Java規範來證明這種行爲是正常的。 1/0拋出一個算術異常,Math.round(Float.NaN)顯然也應該如此。

(這是最驚訝的校長。)

相關問題