Bir sayıyı katlamak için bitsel VEYA 0 kullanma


193

Bir meslektaşım şamandıra sayılarını bitsel olarak katlamak için bir yönteme tökezledi veya:

var a = 13.6 | 0; //a == 13

Bunun hakkında konuşuyorduk ve birkaç şey merak ediyorduk.

  • O nasıl çalışır? Teorimiz, böyle bir operatör kullanmanın sayıyı bir tamsayıya dökmesi ve böylece kesirli kısmı çıkarmasıydı
  • Yapmaya göre herhangi bir avantajı var mı Math.floor? Belki biraz daha hızlı? (cinas amaçlanmamıştır)
  • Herhangi bir dezavantajı var mı? Belki bazı durumlarda işe yaramıyor? Netlik açıktır, çünkü çözmemiz gerekti ve ben de bu soruyu yazıyorum.

Teşekkürler.


6
Dezavantaj: sadece 2 ^ 31−1'e kadar çalışır, bu da 2 milyar civarındadır (10 ^ 9). Maksimum Sayı değeri 10 ^ 308 btw civarındadır.
Šime Vidas

12
Örnek: 3000000000.1 | 0-1294967296 olarak değerlendirilir. Dolayısıyla, bu yöntem para hesaplamaları için uygulanamaz (özellikle ondalık sayıları önlemek için 100 ile çarptığınız durumlarda).
Šime Vidas

13
@ ŠimeVidas Floats para hesaplamalarında da kullanılmamalıdır
George Reith

20
Döşeme değil, kesiliyor (0'a yuvarlama).
Bartłomiej Zalewski

3
@sequence 0.1 + 0.2 == 0.3bir JavaScript konsolu yazmayı deneyin . Diliniz destekliyorsa, ondalık bir tür kullanmalısınız. Değilse, bunun yerine sentleri saklayın.
Alex Turpin

Yanıtlar:


161

O nasıl çalışır? Teorimiz, böyle bir operatör kullanmanın sayıyı bir tamsayıya dökmesi ve böylece kesirli kısmı çıkarmasıydı

İmzasız sağ kaydırma hariç tüm bitsel işlemler >>>, imzalı 32 bit tamsayılar üzerinde çalışır. Bu nedenle bitsel işlemler kullanmak, bir kayan noktayı tamsayıya dönüştürür.

Math.floor yapmaya göre herhangi bir avantajı var mı? Belki biraz daha hızlı? (cinas amaçlanmamıştır)

http://jsperf.com/or-vs-floor/2 biraz daha hızlı görünüyor

Herhangi bir dezavantajı var mı? Belki bazı durumlarda işe yaramıyor? Netlik açıktır, çünkü çözmemiz gerekti ve ben de bu soruyu yazıyorum.

  • JsLint geçmeyecek.
  • Yalnızca 32 bit imzalı tam sayılar
  • Tek Karşılaştırmalı davranışı: Math.floor(NaN) === NaNiken(NaN | 0) === 0

9
@harold, çünkü aslında yuvarlak değil, sadece kesiyor.
Alex Turpin

5
Diğer bir olası dezavantaj Math.floor(NaN) === NaNise (NaN | 0) === 0. Bu fark bazı uygulamalarda önemli olabilir.
Ted Hopp

4
Jsperf'niz, döngü değişmez kod hareketi nedeniyle krom üzerindeki boş döngüler için performans bilgileri sağlıyor. Biraz daha iyi bir perf testi şöyle olurdu: jsperf.com/floor-performance/2
Sam Giles

4
Bu standart bir parçasıdır asm.js(ilk öğrendiğim yer). Başka bir nedenden dolayı daha hızlıdır, çünkü Mathnesne üzerinde bir işlev çağırmaz, her zaman olduğu gibi değiştirilebilen bir işlevdir Math.floor = function(...).
gman

3
(value | 0) === valuebir değerin aslında bir tam sayı ve yalnızca bir tam sayı olup olmadığını kontrol etmek için kullanılabilir (Elm kaynak kodundaki @ dwayne-crooks bağlantılı). Ve foo = foo | 0herhangi bir değeri bir tamsayıya zorlamak için kullanılabilir (32 bitlik sayılar kesilir ve tüm sayılar olmayan 0 olur).
David Michael Gregg

36

Bu, döşemenin aksine kesilmedir . Howard'ın cevabı biraz doğru; Ama bunu Math.floornegatif sayılarla ilgili tam olarak ne yaptığını da ekleyeceğim . Matematiksel olarak, bir zemin budur.

Yukarıda tarif ettiğiniz durumda, programcı kesmeyi veya ondalık kesimi tamamen kesmeyi daha çok istiyordu . Her ne kadar kullandıkları sözdizimi, şamandırayı bir int'e dönüştürdüklerini gizlemektedir.


7
Bu doğru cevap, kabul edilen cevap değil. Math.floor(8589934591.1)Beklenen sonucu üreten buna ekleyin , 8589934591.1 | 0 YAPMAZ .
Salman A

21

ECMAScript 6'da Math.trunc eşdeğeri |0, şunu söylemeliyim:

Herhangi bir kesirli basamağı kaldırarak sayının integral bölümünü döndürür. Argümanın pozitif bir sayı veya negatif bir sayı olması fark etmeksizin sadece noktayı ve arkasındaki rakamları keser.

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

6
Dışında Math.trunc()2 ^ 31 veya daha yüksek sayı ile çalışma ve | 0yok
Nolyurn

10

İlk noktanız doğru. Sayı bir tamsayıya dönüştürülür ve böylece ondalık basamaklar kaldırılır. Unutmayın, bir Math.floorsonraki tamsayı eksi sonsuza yuvarlar ve böylece negatif sayılara uygulandığında farklı bir sonuç verir.


5

Javascript Number, Double Precision 64-bit Kayan sayılar olarak temsil edilir .

Math.floor bunu akılda tutarak çalışır.

Bitsel işlemler 32 bit işaretli tamsayılarda çalışır. 32 bit imzalı tamsayılar ilk biti negatif belirteç olarak kullanır ve diğer 31 bit ise sayıdır. Bu nedenle, izin verilen minimum ve maksimum 32bit işaretli sayılar sırasıyla -2.147.483.648 ve 2147483647'dir (0x7FFFFFFFF).

Yani yaptığınız zaman | 0, esasen yapıyorsunuz & 0xFFFFFFFF. Bu, 0x80000000 (2147483648) veya daha büyük olarak temsil edilen herhangi bir sayının negatif sayı olarak döneceği anlamına gelir.

Örneğin:

 // Safe
 (2147483647.5918 & 0xFFFFFFFF) ===  2147483647
 (2147483647      & 0xFFFFFFFF) ===  2147483647
 (200.59082098    & 0xFFFFFFFF) ===  200
 (0X7FFFFFFF      & 0xFFFFFFFF) ===  0X7FFFFFFF

 // Unsafe
 (2147483648      & 0xFFFFFFFF) === -2147483648
 (-2147483649     & 0xFFFFFFFF) ===  2147483647
 (0x80000000      & 0xFFFFFFFF) === -2147483648
 (3000000000.5    & 0xFFFFFFFF) === -1294967296

Ayrıca. Bitsel işlemler "zemin" yapmaz. Onlar kesmek onlar en yakın yuvarlamak diyerek aynı olan, 0. Negatif sayılara döndüğünüzde, aşağıMath.floor yuvarlar bitsel olarak yukarı yuvarlar .

Daha önce söylediğim gibi Math.floor, daha güvenli çünkü 64bit yüzer sayılarla çalışıyor. Bitsel daha hızlıdır , evet, ancak 32bit imzalı kapsamla sınırlıdır.

Özetlemek:

  • Bitwise, 0 to 2147483647 .
  • Eğer çalışıyorsanız Bitwise 1 numara kapalı -2147483647 to 0 .
  • Bitwise'dan küçük -2147483648ve büyük sayılar için Bitwise tamamen farklıdır2147483647 .

Eğer varsa gerçekten performansı artırmak isteyen ve hem kullanın:

function floor(n) {
    if (n >= 0 && n < 0x80000000) {
      return n & 0xFFFFFFFF;
    }
    if (n > -0x80000000 && n < 0) {
      return (n - 1) & 0xFFFFFFFF;
    }
    return Math.floor(n);
}

Sadece Math.truncbitsel işlemler gibi işler eklemek için . Böylece bunu yapabilirsiniz:

function trunc(n) {
    if (n > -0x80000000 && n < 0x80000000) {
      return n & 0xFFFFFFFF;
    }
    return Math.trunc(n);
}

5
  • Özellikler, bir tamsayıya dönüştürüldüğünü söylüyor:

    Izin vermek ToInt32 (lval).

  • Performans: Bu daha önce jsperf'de test edilmiştir .

not: spec için ölü bağlantı kaldırıldı

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.