Tiêu chuẩn IEEE 754-2008 về Số học dấu phẩy động và Tiêu chuẩn số học độc lập ngôn ngữ (LIA) ISO / IEC 10967, Phần 1 trả lời tại sao lại như vậy.
IEEE 754 § 6.3 Bit dấu
Khi một đầu vào hoặc kết quả là NaN, tiêu chuẩn này không diễn giải dấu hiệu của NaN. Tuy nhiên, lưu ý rằng các hoạt động trên chuỗi bit - copy, negate, abs, copySign - chỉ định bit dấu của kết quả NaN, đôi khi dựa trên bit dấu của toán hạng NaN. Tổng số vị từ logic cũng bị ảnh hưởng bởi bit dấu của toán hạng NaN. Đối với tất cả các hoạt động khác, tiêu chuẩn này không chỉ định bit dấu của kết quả NaN, ngay cả khi chỉ có một NaN đầu vào hoặc khi NaN được tạo ra từ một hoạt động không hợp lệ.
Khi cả đầu vào và kết quả đều không phải là NaN, dấu hiệu của sản phẩm hoặc thương số là HOẶC độc quyền của dấu hiệu toán hạng; dấu của một tổng, hoặc của một sự khác biệt x - y được coi là một tổng x + (y), khác với nhiều nhất là một trong các dấu phụ; và dấu hiệu của kết quả của các chuyển đổi, hoạt động lượng tử hóa, các hoạt động RoundTo-Integral và roundToIntegralExact (xem 5.3.1) là dấu hiệu của toán hạng đầu tiên hoặc duy nhất. Các quy tắc này sẽ được áp dụng ngay cả khi toán hạng hoặc kết quả bằng 0 hoặc vô hạn.
Khi tổng của hai toán hạng có dấu ngược nhau (hoặc chênh lệch của hai toán hạng có dấu giống nhau) chính xác bằng 0, dấu của tổng đó (hoặc chênh lệch) sẽ là +0 trong tất cả các thuộc tính hướng làm tròn trừ roundTowardNegative; trong thuộc tính đó, dấu của tổng bằng 0 (hoặc chênh lệch) chính xác sẽ là −0. Tuy nhiên, x + x = x - (x) vẫn giữ nguyên dấu như x ngay cả khi x bằng không.
Trường hợp bổ sung
Dưới chế độ làm tròn mặc định (Round-to-gần, Ties-to-Thậm chí) , chúng ta thấy rằng x+0.0
sản xuất x
, trừ khi x
được -0.0
: Trong trường hợp đó chúng ta có một tổng của hai toán hạng có dấu hiệu ngược lại có tổng bằng không, và §6.3 đoạn 3 quy tắc bổ sung này tạo ra +0.0
.
Kể từ khi +0.0
không Bitwise giống hệt với bản gốc -0.0
, và đó -0.0
là một giá trị hợp pháp có thể xảy ra như là đầu vào, trình biên dịch có nghĩa vụ để đưa vào mã mà sẽ làm thay đổi số không tiêu cực tiềm năng +0.0
.
Tóm tắt: Trong chế độ làm tròn mặc định, trong x+0.0
, nếux
- là không
-0.0
, sau đó x
bản thân nó là một giá trị đầu ra chấp nhận được.
- là
-0.0
, sau đó giá trị đầu ra phải là +0.0
, không giống hệt bit -0.0
.
Trường hợp nhân
Trong chế độ làm tròn mặc định , không có vấn đề như vậy xảy ra với x*1.0
. Nếu x
:
Trường hợp phép trừ
Trong chế độ làm tròn mặc định , phép trừ x-0.0
cũng là không có, vì nó tương đương với x + (-0.0)
. Nếu x
là
- là
NaN
, sau đó §6.3p1 và §6.2.3 áp dụng theo cách tương tự như đối với phép cộng và phép nhân.
- là
+/- infinity
, sau đó kết quả là +/- infinity
cùng một dấu hiệu.
- là một số (phụ) bình thường,
x-0.0 == x
luôn luôn.
- là
-0.0
, sau đó bởi §6.3p2, chúng ta có " [...] dấu của một tổng, hoặc của một sự khác biệt x - y được coi là một tổng x + (y), khác với nhiều nhất là một trong các dấu cộng; ". Điều này buộc chúng ta phải gán -0.0
như là kết quả của (-0.0) + (-0.0)
, bởi vì -0.0
khác nhau về dấu hiệu từ không có phần bổ sung nào, trong khi +0.0
khác về dấu hiệu của hai phần bổ sung, vi phạm điều khoản này.
- là
+0.0
, sau đó điều này giảm xuống trường hợp bổ sung (+0.0) + (-0.0)
được xem xét ở trên trong Trường hợp bổ sung , mà theo §6.3p3 được quy định để đưa ra +0.0
.
Vì đối với tất cả các trường hợp, giá trị đầu vào là hợp pháp như đầu ra, cho phép xem xét x-0.0
không có giá trị và x == x-0.0
tautology.
Tối ưu hóa thay đổi giá trị
Tiêu chuẩn IEEE 754-2008 có trích dẫn thú vị sau:
IEEE 754 § 10,4 Nghĩa đen và tối ưu hóa thay đổi giá trị
[...]
Các phép biến đổi thay đổi giá trị sau đây, trong số các phép biến đổi khác, bảo tồn nghĩa đen của mã nguồn:
- Áp dụng thuộc tính nhận dạng 0 + x khi x không bằng 0 và không phải là NaN báo hiệu và kết quả có cùng số mũ với x.
- Áp dụng thuộc tính nhận dạng 1 × x khi x không phải là NaN báo hiệu và kết quả có cùng số mũ với x.
- Thay đổi tải trọng hoặc ký bit của một NaN yên tĩnh.
- [...]
Vì tất cả các NaN và tất cả các số nguyên đều có cùng số mũ và kết quả được làm tròn chính xác x+0.0
và x*1.0
cho hữu hạn x
có cùng độ lớn như nhau x
, nên số mũ của chúng là như nhau.
sNaNs
NaN báo hiệu là các giá trị bẫy dấu phẩy động; Chúng là các giá trị NaN đặc biệt có sử dụng làm toán hạng dấu phẩy động dẫn đến ngoại lệ hoạt động không hợp lệ (SIGFPE). Nếu một vòng lặp kích hoạt một ngoại lệ được tối ưu hóa, phần mềm sẽ không còn hoạt động như vậy nữa.
Tuy nhiên, như user2357112 chỉ ra trong các bình luận , Tiêu chuẩn C11 rõ ràng không xác định hành vi báo hiệu NaNs ( sNaN
), do đó trình biên dịch được phép giả sử chúng không xảy ra và do đó, các trường hợp ngoại lệ mà chúng nêu ra cũng không xảy ra. Tiêu chuẩn C ++ 11 bỏ qua mô tả một hành vi để báo hiệu NaN, và do đó cũng không xác định được nó.
Chế độ làm tròn
Trong các chế độ làm tròn thay thế, tối ưu hóa cho phép có thể thay đổi. Chẳng hạn, trong chế độ Round-to-Negative-Infinity , việc tối ưu hóa x+0.0 -> x
trở nên cho phép, nhưng x-0.0 -> x
bị cấm.
Để ngăn GCC giả định các chế độ và hành vi làm tròn mặc định, cờ thử nghiệm -frounding-math
có thể được chuyển cho GCC.
Phần kết luận
Clang và GCC , ngay cả tại -O3
, vẫn tuân thủ chuẩn IEEE-754. Điều này có nghĩa là nó phải tuân theo các quy tắc trên của tiêu chuẩn IEEE-754. x+0.0
là không chút giống hệt nhau để x
cho tất cả x
dưới những quy tắc, nhưng x*1.0
có thể được chọn để được như vậy : Cụ thể, khi chúng ta
- Tuân theo khuyến nghị để không thay đổi tải trọng
x
khi nó là NaN.
- Để lại dấu bit của kết quả NaN không thay đổi
* 1.0
.
- Tuân theo để XOR bit dấu trong một thương / sản phẩm, khi
x
là không một NaN.
Để kích hoạt tối ưu hóa không an toàn của IEEE-754 (x+0.0) -> x
, cờ -ffast-math
cần được chuyển đến Clang hoặc GCC.