อ่านผ่านECMAScript 5.1 สเปค , +0และ-0มีความโดดเด่น
แล้วทำไมไม่+0 === -0ประเมินtrue?
Object.isเพื่อแยกความแตกต่างระหว่าง +0 และ -0
อ่านผ่านECMAScript 5.1 สเปค , +0และ-0มีความโดดเด่น
แล้วทำไมไม่+0 === -0ประเมินtrue?
Object.isเพื่อแยกความแตกต่างระหว่าง +0 และ -0
คำตอบ:
JavaScript ใช้มาตรฐาน IEEE 754เพื่อแสดงตัวเลข จากWikipedia :
ศูนย์ที่ลงนามคือศูนย์ที่มีเครื่องหมายที่เกี่ยวข้อง ในการคำนวณสามัญ -0 = 0 = 0 แต่ในคอมพิวเตอร์บางการแสดงจำนวนอนุญาตให้มีการดำรงอยู่ของสองศูนย์ที่มักจะแสดงโดย-0 (ลบศูนย์)และ0 (ศูนย์บวก) สิ่งนี้เกิดขึ้นในการแสดงตัวเลขที่ลงนามสำหรับจำนวนเต็มและในการแทนจำนวนจุดลอยตัวส่วนใหญ่ หมายเลข 0 มักจะเข้ารหัสเป็น +0 แต่สามารถแสดงด้วย +0 หรือ −0
มาตรฐาน IEEE 754 สำหรับการคำนวณเลขทศนิยม (ปัจจุบันใช้โดยคอมพิวเตอร์ส่วนใหญ่และภาษาการเขียนโปรแกรมที่รองรับหมายเลขจุดลอย) ต้องใช้ทั้ง +0 และ −0 ศูนย์ถือได้ว่าเป็นตัวแปรของบรรทัดจำนวนจริงที่ขยายเพิ่มเช่น 1 / −0 = −∞ และ 1 / + 0 = + ∞การหารด้วยศูนย์จะไม่ได้กำหนดเฉพาะสำหรับ± 0 / ± 0 และ±∞ / ±∞ .
บทความมีข้อมูลเพิ่มเติมเกี่ยวกับการรับรองที่แตกต่างกัน
นี่คือเหตุผลว่าทำไมในทางเทคนิคศูนย์ทั้งสองจึงต้องแยกแยะ
อย่างไรก็ตาม
+0 === -0ประเมินเป็นจริง ทำไม (... )
ลักษณะการทำงานนี้ถูกกำหนดไว้อย่างชัดเจนในส่วน 11.9.6ที่เข้มงวดเท่าเทียมกันเปรียบเทียบอัลกอริทึม (เน้นบางส่วนเหมือง):
การเปรียบเทียบ
x === yที่xและyเป็นค่าผลิตจริงหรือเท็จ การเปรียบเทียบดังกล่าวดำเนินการดังนี้:( ... )
หาก Type (x) คือ Number แสดงว่า
- ถ้า x คือ NaN ให้คืนค่า false
- ถ้า y เป็น NaN ให้ส่งคืน false
- ถ้า x เป็นค่า Number เดียวกับ y ให้ส่งคืนจริง
- ถ้า x เป็น +0 และ y คือ −0 ให้คืนค่าจริง
- ถ้า x คือ −0 และ y คือ +0 ให้คืนค่าจริง
- กลับเท็จ
( ... )
(ถือเดียวกัน+0 == -0btw.)
ดูเหมือนว่ามีเหตุผลในการรักษา+0และ-0เท่ากัน มิฉะนั้นเราจะต้องคำนึงถึงเรื่องนี้ในรหัสของเราและตัวผมเองไม่ต้องการทำเช่นนั้น;)
บันทึก:
ES2015 Object.isแนะนำวิธีการเปรียบเทียบใหม่ Object.isแยกความแตกต่างอย่างชัดเจนระหว่าง-0และ+0:
Object.is(-0, +0); // false
1/0 === Infinity; // true 1/-0 === -Infinity; // true
1 === 1และแต่+0 === -0 1/+0 !== 1/-0แปลกจัง!
+0 !== -0;) ที่สามารถสร้างปัญหาได้จริงๆ
0 !== +0/ 0 !== -0ซึ่งจะสร้างปัญหาเช่นกัน!
ฉันจะเพิ่มนี่เป็นคำตอบเพราะฉันมองข้ามความคิดเห็นของ @ user113716
คุณสามารถทดสอบ -0 ได้โดยทำสิ่งนี้:
function isMinusZero(value) {
return 1/value === -Infinity;
}
isMinusZero(0); // false
isMinusZero(-0); // true
e±308จำนวนของคุณสามารถแสดงได้เฉพาะในรูปแบบ denormalized และการใช้งานที่แตกต่างกันมีความคิดเห็นที่แตกต่างกันเกี่ยวกับสถานที่ที่จะสนับสนุนพวกเขาทั้งหมดหรือไม่ จุดคือในเครื่องบางในบางจุดลอยโหมดหมายเลขของคุณจะแสดงเป็น-0และคนอื่น ๆ 0.000000000000001e-308เป็นจำนวน ลอยตัวได้สนุกมาก
ฉันเพิ่งเจอตัวอย่างที่ +0 และ -0 ประพฤติแตกต่างกันมากจริง ๆ :
Math.atan2(0, 0); //returns 0
Math.atan2(0, -0); //returns Pi
ระวัง: ถึงแม้จะใช้ Math.round กับจำนวนลบเช่น -0.0001 จริง ๆ แล้วก็จะเป็น -0 และสามารถไขการคำนวณที่ตามมาดังที่แสดงไว้ด้านบน
วิธีที่รวดเร็วและสกปรกในการแก้ไขปัญหานี้คือการทำ smth เช่น:
if (x==0) x=0;
หรือเพียงแค่:
x+=0;
นี่จะแปลงตัวเลขเป็น +0 ในกรณีที่เป็น -0
ในมาตรฐาน IEEE 754 ที่ใช้แทนประเภท Number ใน JavaScript เครื่องหมายจะถูกแทนด้วยบิต (1 หมายถึงจำนวนลบ)
0เป็นผลให้มีอยู่ทั้งลบและบวกค่าสำหรับแต่ละจำนวนที่แทนรวมทั้ง
นี่คือเหตุผลที่ทั้งสอง-0และ+0มีอยู่
ตอบชื่อเดิมAre +0 and -0 the same?:
brainslugs83(ในความคิดเห็นของคำตอบโดยSpudley) ชี้ให้เห็นกรณีที่สำคัญที่ +0 และ -0 ใน JS ไม่เหมือนกัน - นำมาใช้เป็นฟังก์ชั่น:
var sign = function(x) {
return 1 / x === 1 / Math.abs(x);
}
สิ่งนี้จะนอกเหนือจากมาตรฐานMath.signกลับเครื่องหมายที่ถูกต้องของ +0 และ -0
มีค่าที่เป็นไปได้สองค่า (การแทนค่าบิต) สำหรับ 0 ค่านี้ไม่ซ้ำกัน โดยเฉพาะอย่างยิ่งในจำนวนจุดลอยตัวนี้สามารถเกิดขึ้นได้ นั่นเป็นเพราะตัวเลขจุดลอยตัวจะถูกจัดเก็บเป็นสูตรจริง
จำนวนเต็มสามารถจัดเก็บในรูปแบบที่แยกกันด้วย คุณสามารถมีค่าตัวเลขด้วยเครื่องหมายบิตเพิ่มเติมดังนั้นในพื้นที่ 16 บิตคุณสามารถเก็บค่าจำนวนเต็ม 15 บิตและเครื่องหมายบิตได้ ในการแทนค่านี้ค่า 1000 (ฐานสิบหก) และ 0000 ทั้งคู่คือ 0 แต่หนึ่งในนั้นคือ +0 และอีกอันคือ -0
สิ่งนี้สามารถหลีกเลี่ยงได้โดยการลบ 1 จากค่าจำนวนเต็มดังนั้นมันอยู่ระหว่าง -1 ถึง -2 ^ 16 แต่สิ่งนี้จะไม่สะดวก
วิธีที่ใช้กันทั่วไปคือการเก็บจำนวนเต็มใน 'การเติมเต็มสองรายการ' แต่ดูเหมือนว่า ECMAscript จะไม่เลือก ในวิธีการนี้ตัวเลขตั้งแต่ 0000 ถึง 7FFF บวก ตัวเลขติดลบเริ่มต้นที่ FFFF (-1) ถึง 8000
แน่นอนว่ากฎเดียวกันนี้ใช้กับจำนวนเต็มที่มากขึ้นด้วย แต่ฉันไม่ต้องการให้ F ของฉันเสื่อมสภาพ ;)
+0 === -0แปลก ๆ เพราะตอนนี้เรามี1 === 1และ+0 === -0แต่1/+0 !== 1/-0...
+0 === -0แม้ว่าการรับรองสองบิตจะแตกต่างกัน
เราสามารถใช้Object.isในการแยกแยะและ 0 -0 NaN==NaNและสิ่งหนึ่งที่มากขึ้น
Object.is(+0,-0) //false
Object.is(NaN,NaN) //true
ฉันโทษมันในวิธีการเปรียบเทียบความเท่าเทียมกันอย่างเข้มงวด ('===') ดูหัวข้อ 4d

ดู7.2.13 การเปรียบเทียบความเท่าเทียมอย่างเข้มงวดในข้อกำหนด
Wikipedia มีบทความที่ดีที่จะอธิบายปรากฏการณ์นี้: http://en.wikipedia.org/wiki/Signed_zero
กล่าวโดยสรุปคือทั้ง +0 และ -0 ถูกกำหนดไว้ในข้อกำหนดคุณสมบัติ IEEE floating point พวกเขาทั้งสองมีความแตกต่างทางเทคนิคจาก 0 โดยไม่มีสัญญาณซึ่งเป็นจำนวนเต็ม แต่ในทางปฏิบัติพวกเขาทั้งหมดประเมินเป็นศูนย์ดังนั้นความแตกต่างสามารถถูกละเว้นสำหรับวัตถุประสงค์ในทางปฏิบัติทั้งหมด