อ่านผ่าน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 == -0
btw.)
ดูเหมือนว่ามีเหตุผลในการรักษา+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 โดยไม่มีสัญญาณซึ่งเป็นจำนวนเต็ม แต่ในทางปฏิบัติพวกเขาทั้งหมดประเมินเป็นศูนย์ดังนั้นความแตกต่างสามารถถูกละเว้นสำหรับวัตถุประสงค์ในทางปฏิบัติทั้งหมด