มาตรฐาน IEEE 754-2008 สำหรับเลขคณิต Floating-Point และมาตรฐาน ISO / IEC 10967 Language Independent Arithmetic (LIA) ตอนที่ 1 เป็นคำตอบว่าเหตุใดจึงเป็นเช่นนั้น
IEEE 754 § 6.3 บิตเครื่องหมาย
เมื่ออินพุตหรือผลลัพธ์เป็น NaN มาตรฐานนี้จะไม่ตีความสัญลักษณ์ของ NaN อย่างไรก็ตามโปรดทราบว่าการดำเนินการกับสตริงบิต - คัดลอกลบล้างเอบีเอส copySign ระบุบิตเครื่องหมายของผลลัพธ์ NaN บางครั้งขึ้นอยู่กับบิตเครื่องหมายของตัวถูกดำเนินการ NaN TotalOrder เพรดิเคตเชิงตรรกะยังได้รับผลกระทบจากบิตเครื่องหมายของตัวถูกดำเนินการ NaN สำหรับการดำเนินการอื่น ๆ มาตรฐานนี้ไม่ได้ระบุบิตเครื่องหมายของผลลัพธ์ NaN แม้ว่าจะมี NaN อินพุตเดียวหรือเมื่อ NaN ถูกสร้างขึ้นจากการดำเนินการที่ไม่ถูกต้อง
เมื่อไม่มีอินพุตหรือผลลัพธ์เป็น NaN เครื่องหมายของผลิตภัณฑ์หรือผลหารจะเป็นเอกสิทธิ์เฉพาะหรือของสัญญาณของตัวถูกดำเนินการ เครื่องหมายของผลรวมหรือผลต่าง x - y ถือเป็นผลรวม x + (−y) แตกต่างจากเครื่องหมายบวกส่วนใหญ่ และเครื่องหมายของผลลัพธ์ของการแปลงการดำเนินการเชิงปริมาณการดำเนินการ roundTo-Integral และ roundToIntegralExact (ดู 5.3.1) เป็นเครื่องหมายของตัวถูกดำเนินการตัวแรกหรือตัวเดียว กฎเหล่านี้จะใช้แม้ว่าตัวถูกดำเนินการหรือผลลัพธ์จะเป็นศูนย์หรือไม่มีที่สิ้นสุด
เมื่อผลรวมของสองตัวถูกดำเนินการที่มีเครื่องหมายตรงข้าม (หรือผลต่างของตัวถูกดำเนินการสองตัวที่มีสัญลักษณ์เหมือนกัน) เป็นศูนย์พอดีเครื่องหมายของผลรวมนั้น (หรือผลต่าง) จะเป็น +0 ในแอตทริบิวต์ทิศทางการปัดเศษทั้งหมดยกเว้น roundTowardNegative ภายใต้แอตทริบิวต์นั้นเครื่องหมายของผลรวมศูนย์ที่แน่นอน (หรือผลต่าง) จะต้องเป็น −0 อย่างไรก็ตาม x + x = x - (−x) ยังคงมีเครื่องหมายเดียวกับ x แม้ว่า x จะเป็นศูนย์ก็ตาม
กรณีของการเพิ่ม
ภายใต้โหมดการปัดเศษเริ่มต้น (Round-to-Nearest, Ties-to-Even)เราจะเห็นว่าx+0.0
สร้างx
ขึ้นยกเว้นเมื่อx
เป็น-0.0
: ในกรณีนั้นเรามีผลรวมของสองตัวถูกดำเนินการที่มีเครื่องหมายตรงข้ามซึ่งผลรวมเป็นศูนย์และ§6.3ย่อหน้า 3 +0.0
กฎนอกจากนี้ผลิต
เนื่องจาก+0.0
ไม่ได้เป็นบิตเหมือนกันกับต้นฉบับ-0.0
และนั่น-0.0
เป็นค่าที่ถูกต้องซึ่งอาจเกิดขึ้นเป็นอินพุตคอมไพเลอร์จึงจำเป็นต้องใส่รหัสที่จะเปลี่ยนค่าศูนย์ลบที่อาจเกิดขึ้นเป็น+0.0
เป็น
สรุป: ภายใต้โหมดการปัดเศษเริ่มต้นในx+0.0
ถ้าx
- ไม่ได้
-0.0
แล้วx
ตัวเองเป็นมูลค่าการส่งออกได้รับการยอมรับ
- คือ
-0.0
ค่าเอาต์พุตจะต้องเป็น +0.0
ซึ่งไม่เหมือนกับบิตคอย-0.0
น์
กรณีของการคูณ
ภายใต้โหมดเริ่มต้นการปัดเศษx*1.0
ไม่มีปัญหาดังกล่าวเกิดขึ้นกับ ถ้าx
:
กรณีของการลบ
ภายใต้โหมดการปัดเศษเริ่มต้น , การลบx-0.0
ยังเป็น no-op x + (-0.0)
เพราะมันจะเทียบเท่ากับ ถ้าx
เป็น
- คือ
NaN
แล้ว§6.3p1และ§6.2.3จะใช้ในลักษณะเดียวกับการบวกและการคูณ
- เป็น
+/- infinity
แล้วผลที่ได้คือ+/- infinity
การเข้าสู่ระบบเดียวกัน
- เป็น (ย่อย) จำนวนปกติ
x-0.0 == x
เสมอ
- คือ
-0.0
แล้วโดย§6.3p2เรามี " [... ] เครื่องหมายของผลรวมหรือผลต่าง x - y ถือเป็นผลรวม x + (−y) แตกต่างจากเครื่องหมายบวกส่วนใหญ่ " กองกำลังนี้เราจะกำหนด-0.0
เป็นผลมาจาก(-0.0) + (-0.0)
เพราะ-0.0
ความแตกต่างในการเข้าสู่ระบบจากใครของ addends ในขณะที่+0.0
มีความแตกต่างในการเข้าสู่ระบบจากสองส่วนที่เพิ่มซึ่งเป็นการละเมิดข้อนี้
- คือ
+0.0
จากนั้นสิ่งนี้จะลดลงเป็นกรณีการเพิ่มที่(+0.0) + (-0.0)
พิจารณาข้างต้นในกรณีของการเพิ่ม+0.0
ซึ่งโดย§6.3p3ถูกปกครองที่จะให้
เนื่องจากสำหรับทุกกรณีค่าอินพุตถูกต้องตามกฎหมายเป็นเอาต์พุตจึงอนุญาตให้พิจารณาx-0.0
no-op และx == x-0.0
tautology ได้
การเพิ่มประสิทธิภาพการเปลี่ยนแปลงมูลค่า
มาตรฐาน IEEE 754-2008 มีคำพูดที่น่าสนใจดังต่อไปนี้:
IEEE 754 § 10.4 ความหมายตามตัวอักษรและการปรับเปลี่ยนค่าให้เหมาะสม
[ ... ]
การแปลงค่าที่เปลี่ยนแปลงต่อไปนี้และอื่น ๆ รักษาความหมายตามตัวอักษรของซอร์สโค้ด:
- การใช้คุณสมบัติเอกลักษณ์ 0 + x เมื่อ x ไม่ใช่ศูนย์และไม่ใช่ NaN การส่งสัญญาณและผลลัพธ์จะมีเลขชี้กำลังเหมือนกับ x
- การใช้คุณสมบัติเอกลักษณ์ 1 × x เมื่อ x ไม่ใช่ NaN การส่งสัญญาณและผลลัพธ์จะมีเลขชี้กำลังเหมือนกับ x
- การเปลี่ยน payload หรือ sign bit ของ NaN ที่เงียบ
- [ ... ]
เนื่องจาก NaN ทั้งหมดและ infinities ทั้งหมดมีเลขชี้กำลังเหมือนกันและผลลัพธ์ที่ถูกปัดเศษอย่างถูกต้องของx+0.0
และx*1.0
สำหรับ จำกัดx
มีขนาดเท่าx
กันทุกประการเลขชี้กำลังจึงเหมือนกัน
sNaNs
NaN การส่งสัญญาณคือค่ากับดักจุดลอยตัว เป็นค่า NaN พิเศษที่ใช้เป็นตัวถูกดำเนินการจุดลอยตัวทำให้เกิดข้อยกเว้นการดำเนินการที่ไม่ถูกต้อง (SIGFPE) หากลูปที่ทำให้เกิดข้อยกเว้นถูกปรับให้เหมาะสมซอฟต์แวร์จะไม่ทำงานเหมือนเดิมอีกต่อไป
อย่างไรก็ตามตามที่ user2357112 ชี้ให้เห็นในความคิดเห็น C11 Standard จะทิ้งพฤติกรรมการส่งสัญญาณ NaNs ( sNaN
) โดยไม่ได้กำหนดไว้อย่างชัดเจนดังนั้นคอมไพเลอร์จึงได้รับอนุญาตให้ถือว่าสิ่งเหล่านี้ไม่เกิดขึ้นและดังนั้นจึงไม่มีข้อยกเว้นที่พวกเขาเพิ่มขึ้นเช่นกัน มาตรฐาน C ++ 11 จะละเว้นที่อธิบายถึงพฤติกรรมในการส่งสัญญาณ NaN และทำให้ไม่ได้กำหนดไว้
โหมดการปัดเศษ
ในโหมดการปัดเศษอื่นการเพิ่มประสิทธิภาพที่อนุญาตอาจเปลี่ยนแปลงได้ ตัวอย่างเช่นภายใต้โหมดRound-to-Negative-Infinityการเพิ่มประสิทธิภาพx+0.0 -> x
จะได้รับอนุญาต แต่x-0.0 -> x
จะถูกห้าม
เพื่อป้องกันไม่ให้ GCC สมมติว่าเป็นโหมดและพฤติกรรมการปัดเศษเริ่มต้น-frounding-math
คุณสามารถส่งค่าสถานะทดลองไปยัง GCC ได้
ข้อสรุป
เสียงดังกราวและGCCแม้ที่-O3
ยังคงมาตรฐาน IEEE-754 ตามมาตรฐาน ซึ่งหมายความว่าจะต้องปฏิบัติตามกฎข้างต้นของมาตรฐาน IEEE-754 x+0.0
คือไม่บิตเหมือนกันไปx
ทั้งหมดx
ภายใต้กฎระเบียบเหล่านั้น แต่x*1.0
อาจจะเลือกที่จะให้ : คือเมื่อเรา
- ปฏิบัติตามคำแนะนำเพื่อส่งผ่าน payload ที่ไม่มีการเปลี่ยนแปลง
x
เมื่อเป็น NaN
* 1.0
ปล่อยบิตเครื่องหมายของน่านส่งผลให้เกิดการเปลี่ยนแปลงโดย
- เชื่อฟังคำสั่งให้แฮคเกอร์บิตเครื่องหมายระหว่างความฉลาดทาง / สินค้าเมื่อ
x
เป็นไม่น่าน
ในการเปิดใช้งานการเพิ่มประสิทธิภาพ IEEE-754 ที่ไม่ปลอดภัยต้องส่ง(x+0.0) -> x
แฟ-ffast-math
ล็กไปยัง Clang หรือ GCC