~~ (“ tilde คู่”) ทำอะไรใน Javascript


205

ฉันกำลังตรวจสอบคลังฟิสิกส์เกมออนไลน์ในวันนี้และเจอผู้ให้บริการ ~~ ฉันรู้ว่าซิงเกิ้ล ~ คือ bitwise ไม่, นั่นจะทำให้ ~~ ไม่ใช่อันไหน, ซึ่งจะคืนค่าเดียวกัน, ใช่ไหม?


คำตอบ:


248

มันจะลบทุกอย่างหลังจากจุดทศนิยมเพราะตัวดำเนินการ bitwise แปลงตัวถูกดำเนินการโดยปริยายของพวกเขาเป็นจำนวนเต็ม 32 บิตลงนาม สิ่งนี้ทำงานได้อย่างไรว่าตัวถูกดำเนินการเป็นตัวเลขหรือสตริง (เลขทศนิยม) และผลลัพธ์คือตัวเลข

กล่าวอีกนัยหนึ่งมันทำให้:

function(x) {
  if(x < 0) return Math.ceil(x);
  else return Math.floor(x);
}

เฉพาะในกรณีที่xอยู่ระหว่าง - (2 31 ) และ 2 31 - 1 มิฉะนั้นจะเกิดโอเวอร์โฟลว์และจำนวนจะ "ล้อมรอบ"

นี่อาจเป็นประโยชน์ในการแปลงอาร์กิวเมนต์สตริงของฟังก์ชันเป็นตัวเลข แต่ทั้งคู่เนื่องจากความเป็นไปได้ของการโอเวอร์โฟลว์และมันไม่ถูกต้องสำหรับใช้กับไม่ใช่จำนวนเต็มฉันจะไม่ใช้วิธีนั้นยกเว้น "code golf" ( เช่นไบต์การตัดอย่างไม่มีจุดหมายออกจากซอร์สโค้ดของโปรแกรมของคุณ ฉันจะใช้+xหรือNumber(x)แทน


นี่คือสิ่งที่ไม่ใช่ของไม่

จำนวน -43.2 ตัวอย่างเช่น:

-43.2 10 = 1111111111111111111111111111010101 2

เป็นเลขฐานสองแบบ 32 บิตที่เซ็นชื่อแล้ว (JavaScript จะข้ามสิ่งที่อยู่หลังจุดทศนิยม) การแปลงบิตให้เป็น:

NOT -43 10 = 00000000000000000000000000101010 2 = 42 10

Inverting ให้อีกครั้ง:

Not 42 10 = 1111111111111111111111111111010101 2 = -43 10

สิ่งนี้แตกต่างจากMath.floor(-43.2)จำนวนลบที่ปัดเศษเป็นศูนย์ไม่ใช่ห่างจากมัน (ฟังก์ชัน floor ซึ่งจะเท่ากับ -44 จะปัดเศษเป็นจำนวนเต็มถัดไปเสมอโดยไม่คำนึงว่าหมายเลขนั้นเป็นบวกหรือลบ)


6
ซึ่งก็คือการบอกว่า~~เป็นวิธีที่จดชวเลข (และอาจจะเป็นทางออกที่ดี?) สำหรับการสร้างฟังก์ชั่นตัดแต่อย่างเห็นได้ชัดใน JavaScript
ruffin

4
JSLint ~~จะบ่นเกี่ยวกับการใช้งานของ
Richard Cook

1
ลอง Math.trunc ()
Xitalogy

30

ตัวดำเนินการ ~ แรกจะบังคับให้ตัวถูกดำเนินการเป็นจำนวนเต็ม (อาจเป็นไปได้หลังจากการบีบบังคับค่าให้กับสตริงหรือบูลีน) จากนั้นกลับค่าต่ำสุด 31 บิต หมายเลข ECMAScript อย่างเป็นทางการคือจำนวนจุดลอยตัวทั้งหมด แต่ตัวเลขบางส่วนถูกนำไปใช้เป็นจำนวนเต็ม 31 บิตในโปรแกรม SpiderMonkey

คุณสามารถใช้มันเพื่อเปลี่ยนอาร์เรย์ 1 องค์ประกอบให้เป็นจำนวนเต็ม คะแนนแบบลอยจะถูกแปลงตามกฎ C เช่น การตัดส่วนที่เป็นเศษส่วน

ตัวดำเนินการ ~ อันที่สองจะแปลงบิตกลับมาดังนั้นคุณจึงรู้ว่าคุณจะมีจำนวนเต็ม สิ่งนี้ไม่เหมือนกับการบังคับค่าบูลีนในคำสั่งเงื่อนไขเนื่องจากวัตถุว่าง {} ประเมินค่าเป็นจริงในขณะที่ ~~ {} จะประเมินค่าเป็นเท็จ

js>~~"yes"
0
js>~~3
3
js>~~"yes"
0
js>~~false
0
js>~~""
0
js>~~true
1
js>~~"3"
3
js>~~{}
0
js>~~{a:2}
0
js>~~[2]
2
js>~~[2,3]
0
js>~~{toString: function() {return 4}}
4
js>~~NaN
0
js>~~[4.5]
4
js>~~5.6
5
js>~~-5.6
-5

1
ขอบคุณสำหรับตัวอย่างทั้งหมดที่นี่ Shanti มันช่วยได้จริงๆ!
เชนทอมลินสัน

6
ยัง~~undefined // 0
rampion

1
ยัง~~null // 0
chovy

ในทางเทคนิคคุณมีลำดับที่ไม่ถูกต้อง ที่สอง~ทำในสิ่งที่คุณอธิบายไว้เป็นครั้งแรก~และในทางกลับกัน ~ผู้ประกอบการเป็นผู้ประกอบการเอกภาคและ interpereted จากขวาไปซ้าย~~Xก็เหมือน~(~X)ไม่เหมือน(~~)X(ซึ่งจะเป็นข้อผิดพลาดทางไวยากรณ์)
yunzen

20

ใน ECMAScript 6 ค่าเทียบเท่า~~คือMath.trunc :

ส่งคืนส่วนหนึ่งของตัวเลขโดยการลบเศษส่วนใด ๆ มันไม่ได้ปัดเศษตัวเลขใด ๆ

Math.trunc(13.37)   // 13
Math.trunc(42.84)   // 42
Math.trunc(0.123)   //  0
Math.trunc(-0.123)  // -0
Math.trunc("-1.123")// -1
Math.trunc(NaN)     // NaN
Math.trunc("foo")   // NaN
Math.trunc()        // NaN

The polyfill:

function trunc(x) {
    return x < 0 ? Math.ceil(x) : Math.floor(x);
}

6
ค่อนข้างน่าแปลกใจ ~~ จะเร็วกว่า Math.trunc, jsperf.com/math-trunc-vs-double-bitwise-not-operator แม้ว่าทุกอย่างจะไม่เกี่ยวกับความเร็ว การอ่านด้วย
Gajus

3
มีความแตกต่างที่สำคัญระหว่าง ~~ และ Math.trunc: ถ้าคุณผ่านสตริงหรือ NaN หรืออะไรก็ตามที่ไม่ใช่ตัวเลข Math.trunc จะคืน NaN และ ~~ จะส่งกลับตัวเลขเสมอในกรณีเหล่านั้นมัน จะกลับ 0
บูซินัส

Math.trunc เป็นเล็กน้อยเร็วกว่า ~~ ใน Chrome 59+ ตามjsperf.com/math-trunc-vs-double-bitwise-not-operator
Jack Steam

12

~ดูเหมือนว่าจะทำ-(N+1)ดูเหมือนว่าจะทำดังนั้น~2 == -(2 + 1) == -3หากคุณทำมันอีกครั้งในวันที่ -3 มันจะย้อนกลับ: ~-3 == -(-3 + 1) == 2มันอาจจะแปลงสตริงเป็นตัวเลขในทางกลับกัน

ดูกระทู้นี้: http://www.sitepoint.com/forums/showthread.php?t=663275

นอกจากนี้ยังมีข้อมูลรายละเอียดเพิ่มเติมที่นี่: http://dreaminginjavascript.wordpress.com/2008/07/04/28/


ขอบคุณสำหรับลิงค์ Drackir!
เชนทอมลินสัน

7

ได้รับ~Nมี-(N+1), เป็นแล้ว~~N -(-(N+1) + 1)ซึ่งเห็นได้ชัดว่าจะนำไปสู่เคล็ดลับเรียบร้อย


ต้องเลื่อนลงไปที่ความคิดเห็นของแมตต์ที่จะเห็นมันในการใช้งานที่เหมาะสม;)
mplungjan

4

แค่คำเตือนนิดหน่อย คำตอบอื่น ๆ ที่นี่ทำให้ฉันมีปัญหาบางอย่าง

ความตั้งใจคือการลบสิ่งใด ๆ หลังจากจุดทศนิยมของตัวเลขทศนิยม แต่ก็มีบางกรณีมุมที่ทำให้มันเป็นอันตรายจากแมลง ฉันขอแนะนำให้หลีกเลี่ยง ~~

ก่อนอื่น ~~ ไม่ทำงานกับตัวเลขที่มีขนาดใหญ่มาก

~~1000000000000 == -727279968

ในฐานะที่เป็นทางเลือกให้ใช้Math.trunc()(ดังที่ Gajus พูดถึงMath.trunc()ส่งคืนส่วนจำนวนเต็มของตัวเลขจำนวนจุดลอยตัว แต่มีให้เฉพาะใน JavaScript ที่สอดคล้องกับ ECMAScript 6) คุณสามารถสร้างของคุณเองMath.trunc()สำหรับสภาพแวดล้อมที่ไม่ใช่ ECMAScript-6 ได้โดยทำสิ่งนี้:

if(!Math.trunc){
    Math.trunc = function(value){
        return Math.sign(value) * Math.floor(Math.abs(value));
    }
}

ฉันเขียนบทความในบล็อกนี้เพื่อใช้อ้างอิง: http://bitlords.blogspot.com/2016/08/the-double-tilde-x-technique-in.html



1

การแปลงสตริงเป็นตัวเลข

console.log(~~-1);    // -1
console.log(~~0);     // 0
console.log(~~1);     // 1
console.log(~~"-1");  // -1
console.log(~~"0");   // 0
console.log(~~"1");   // 1
console.log(~~true);  // 1
console.log(~~false); // 0

~ -1 คือ 0

if (~someStr.indexOf("a")) {
  // Found it
} else  {
  // Not Found
}

แหล่ง


1

Tilde (~) มี algorihm - (N + 1)

สำหรับสอบ:

~0 = -(0+1) = -1
~5 = -(5+1) = -6
~-7 = -(-7+1) = 6

ตัวหนอนคู่คือ - (- (N + 1) +1)

ตัวอย่างเช่น:

~~5 = -(-(5+1)+1) = 5
~~-3 = -(-(-3+1)+1) = -3

ตัวหนอนสามตัวคือ - (- (- ((+ 1) +1) +1)

ตัวอย่างเช่น:

~~~2 = -(-(-(2+1)+1)+1) = -3
~~~3 = -(-(-(3+1)+1)+1) = -4
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.