~~ (“double tilde”) Javascript'te ne yapıyor?


Yanıtlar:


248

Ondalık noktadan sonraki her şeyi kaldırır, çünkü bitsel işleçler işlenenlerini örtük olarak işaretli 32 bit tamsayılara dönüştürür. Bu, işlenenlerin (kayan nokta) sayı mı yoksa dizgi mi olduğu ve sonuç bir sayı mı olduğu ile çalışır.

Başka bir deyişle, şunu verir:

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

yalnızca x - (2 31 ) ve 2 31 - 1 arasındaysa. Aksi takdirde taşma meydana gelir ve sayı "etrafına sarılır".

Bu, bir işlevin dize bağımsız değişkenini bir sayıya dönüştürmek için yararlı kabul edilebilir, ancak her ikisi de taşma olasılığı ve tamsayı olmayanlarla kullanım için yanlış olduğundan, "kod golf" ( yani okunabilirlik ve sağlamlık pahasına programınızın kaynak kodunu gereksiz yere kırpmak). Ben kullanacağı +xveya Number(x)onun yerine.


Bu NOT DEĞİL nasıl

Örneğin, -43.2 sayısı:

-43,2 10 = 11111111111111111111111111010101 2

imzalı (ikisinin tamamlayıcısı) 32 bit ikili sayı olarak. (JavaScript ondalık noktadan sonra olanları yok sayar.) Bitleri ters çevirmek şunları sağlar:

-43 10 DEĞİL = 00000000000000000000000000101010 2 = 42 10

Tekrar tersine çevirme:

NOT 42 10 = 11111111111111111111111111010101 2 = -43 10

Bu Math.floor(-43.2), negatif sayıların ondan uzakta değil, sıfıra yuvarlanması bakımından farklılık gösterir . (Sayının pozitif veya negatif olmasına bakılmaksızın, -44'e eşit olan zemin işlevi her zaman bir sonraki düşük tamsayıya yuvarlar.)


6
~~Demek ki, kısmi bir işlev oluşturmak için kısa bir yol (ve muhtemelen iyi bir çözüm?) , Ancak açık bir şekilde javascript .
ruffin

4
JSLint kullanımı hakkında şikayet edecek ~~.
Richard Cook

1
Math.trunc ()
Xitalogy

30

İlk operatör, işleneni bir tamsayıya zorlar (muhtemelen değeri bir dizeye veya boole değerine zorladıktan sonra), ardından en düşük 31 biti tersine çevirir. Resmi olarak ECMAScript sayılarının hepsi kayan noktalı, ancak bazı sayılar SpiderMonkey motorunda 31 bit tamsayı olarak uygulanır.

1 elemanlı bir diziyi bir tamsayıya dönüştürmek için kullanabilirsiniz. Kayan noktalar C kuralına göre dönüştürülür, yani. kesirli kısmın kesilmesi.

İkinci operatör daha sonra bitleri tersine çevirir, böylece bir tamsayı elde edeceğinizi bilirsiniz. Bu, koşul ifadesinde boole değerine zorlamakla aynı şey değildir, çünkü boş bir nesne {} doğru olarak değerlendirirken ~~ {} yanlış olarak değerlendirir.

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
Buradaki tüm örnekler için teşekkürler Shanti, gerçekten yardımcı oldu!
Shane Tomlinson

6
ayrıca~~undefined // 0
rampion

1
ayrıca~~null // 0
chovy

Teknik olarak yanlış siparişiniz var. İkincisi ~, ilk yaptığınız ~şeyi yapar ve tersi de geçerlidir. ~Operatör bir tekli operatörler ve sağdan sola doğru interpereted edilir ~~Xgibidir ~(~X)değil gibi (~~)X(ki bir yazım hatası olacaktır)
yunzen

20

ECMAScript'te 6'da, eşdeğer ~~olan Math.trunc :

Herhangi bir kesirli basamağı kaldırarak sayının integral bölümünü döndürür. Herhangi bir sayıyı yuvarlamaz.

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

Çok dolgu:

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

6
Biraz şaşırtıcı bir şekilde, ~~ Math.trunc'dan daha hızlıdır, jsperf.com/math-trunc-vs-double-bitwise-not-operator . Yine de, her şey hız ile ilgili değildir; okunabilirlik de.
Aralık'ta Gajus

3
~~ ve Math.trunc arasında önemli bir fark vardır: Eğer bir dize veya NaN veya sayı olmayan herhangi bir şey iletirseniz, Math.trunc NaN döndürür ve ~~ her zaman bir sayı döndürür, bu durumlarda, 0
Buzinas

Math.trunc göre marjinal hızlı Krom 59 + içinde ~~ daha jsperf.com/math-trunc-vs-double-bitwise-not-operator .
Jack Steam



4

Sadece bir uyarı. Buradaki diğer cevaplar beni biraz belaya soktu.

Amaç, kayan nokta sayısının ondalık noktasından sonra herhangi bir şeyi kaldırmaktır, ancak hata tehlikesi haline getiren bazı köşe vakaları vardır. Kaçınmayı tavsiye ederim ~~.

İlk olarak, ~~ çok büyük sayılar üzerinde çalışmaz.

~~1000000000000 == -727279968

Alternatif olarak, kullanın Math.trunc()(Gajus'un belirttiği gibi, Math.trunc()bir kayan nokta sayısının tamsayı kısmını döndürür, ancak yalnızca ECMAScript 6 uyumlu JavaScript'te kullanılabilir). Bunu Math.trunc()yaparak ECMAScript-6 dışındaki ortamlar için her zaman kendi ortamınızı oluşturabilirsiniz:

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

Bu konuda referans için bir blog yazısı yazdım: http://bitlords.blogspot.com/2016/08/the-double-tilde-x-technique-in.html


1

İşte bu operatörün verimli bir şekilde nasıl kullanılabileceğine, onu kullanmanın mantıklı olduğu bir örnek:

leftOffset = -(~~$('html').css('padding-left').replace('px', '') + ~~$('body').css('margin-left').replace('px', '')),

Kaynak:

Noktalarla etkileşim bölümüne bakın.


1

Dizeleri Sayılara Dönüştürme

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
}

kaynak


1

Tilde (~) bir algoritmaya sahiptir - (N + 1)

Sınav için:

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

Çift dalga işareti - (- (N + 1) +1)

Örneğin:

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

Üçlü yaklaşık işareti - (- (- (N + 1) +1) +1)

Örneğin:

~~~2 = -(-(-(2+1)+1)+1) = -3
~~~3 = -(-(-(3+1)+1)+1) = -4
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.