Yanıtlar:
Bir sayı y
ve bazı bölen x
için ( quotient
) ve kalan ( remainder
) bölümünü şu şekilde hesaplayın :
var quotient = Math.floor(y/x);
var remainder = y % x;
floor
ve %
birlikte kullanmak bu şekilde tutarlı değildir. Ya (negatif geri kalanlara izin vermek) trunc
yerine kullanın floor
ya da geri kalanını almak için çıkarma kullanın ( rem = y - div * x
).
rem
neyse, bölüm elde edebilirsiniz div
döşeme olmadan daha hızlı: (y - rem) / x
. 2. Bu arada, Donald Knuth'un önerilen tanımı (işaret-maç-bölen, geri kalan yani Öklid modülü veya JavaScript işaret-maç-bölme) tarafından modulo işlemi JavaScript olarak kodlayabileceğimiz şeydir function mod (a, n) { return a % n + (Math.sign(a) !== Math.sign(n) ? n : 0); }
.
Bitsel operatörler konusunda uzman değilim, ancak tüm sayıyı almanın başka bir yolu:
var num = ~~(a / b);
Bu, negatif sayılar için de düzgün çalışacak Math.floor()
, yanlış yönde yuvarlanacaktır.
Bu da doğru görünüyor:
var num = (a / b) >> 0;
a/b | 0
~~int
, int | 0
Ve int >> 0
ilk bağımsız değişken değiştirmez, ancak yorumlayıcı operatöre parçasını geçmesi olun.
floor
adı göz önüne alındığında neredeyse yanlış yöne yuvarlanmıyor - insanların genellikle istediği yönü değil!
a = 12447132275286670000; b = 128
Math.floor(a/b)
-> 97243220900677100
ve ~~(a/b)
-> -1231452688
.
~~(5/2) --> 2
olduğu gibi (5/2)>>0 --> 2
, ama ~~(5/2) + 1 --> 3
süre ~~(5/2)>>0 + 1 --> 1
. ~~
iyi bir seçimdir çünkü öncelik daha uygundur.
Firefox'ta bazı hız testleri yaptım.
-100/3 // -33.33..., 0.3663 millisec
Math.floor(-100/3) // -34, 0.5016 millisec
~~(-100/3) // -33, 0.3619 millisec
(-100/3>>0) // -33, 0.3632 millisec
(-100/3|0) // -33, 0.3856 millisec
(-100-(-100%3))/3 // -33, 0.3591 millisec
/* a=-100, b=3 */
a/b // -33.33..., 0.4863 millisec
Math.floor(a/b) // -34, 0.6019 millisec
~~(a/b) // -33, 0.5148 millisec
(a/b>>0) // -33, 0.5048 millisec
(a/b|0) // -33, 0.5078 millisec
(a-(a%b))/b // -33, 0.6649 millisec
Yukarıda belirtilenler her biri için 10 milyon denemeye dayanmaktadır.
Sonuç: Kullanım (a/b>>0)
(veya (~~(a/b))
veya (a/b|0)
) verimliliğinde 20 yaklaşık% kazancı elde etmek. Ayrıca, bunların Math.floor
ne zaman tutarsız olduklarını da unutmayın a/b<0 && a%b!=0
.
Math.floor
diğer API işlevlerini ve kimin bildiklerini öğrenmek ya da ~
(bitsel-değil) operatörü ve JS'de bitsel işlemlerin nasıl çalıştığını öğrenmek ve daha sonra çift tilde etkisini anlamak ?
Math.floor
daha iyi anlayacaklardır . Ve olmasa bile, bu googleable.
ES6 yeni Math.trunc
yöntemi tanıttı . Bu, @ MarkElliot'un cevabını negatif sayılar için de çalışmasını sağlamak için düzeltmeye izin verir :
var div = Math.trunc(y/x);
var rem = y % x;
Math
Yöntemlerin, 2 31 üzerindeki sayılarla çalıştıkları bitsel işleçlere göre avantajları olduğunu unutmayın .
18014398509481984 == 18014398509481985
,.
~~(x/y)
. 54 bite kadar imzalanmış daha büyük sayıları desteklemeniz mi gerekiyor? Math.trunc
Elinizde varsa kullanın veya Math.floor
başka bir şekilde (negatif sayılar için doğru). Daha büyük sayıları desteklemeniz mi gerekiyor? Bazı büyük sayı kitaplıkları kullanın.
divmod
, bunu şöyle uygulayabilirsiniz:function divmod(x, y) { var div = Math.trunc(x/y); var rem = x % y; return [div, rem]; }
var remainder = x % y;
return (x - remainder) / y;
Math.trunc
:) kullanan yöntemle aynı değerleri döndürür . 100,3 ile kontrol ettim; -100,3; 100, -3 ve -100, -3. Tabii ki, yorumunuz ve işler değiştikten sonra çok zaman geçti.
Normalde kullanıyorum:
const quotient = (a - a % b) / b;
const remainder = a % b;
Muhtemelen en zarif değil, ama işe yarıyor.
parseInt
Kesilmiş bir sonuç elde etmek için işlevi kullanabilirsiniz .
parseInt(a/b)
Geriye kalanları almak için mod operatörünü kullanın:
a%b
parseInt, taban 10 ile radix parametresini kullanmaktan kaçınmak için dizeleri olan bazı tuzaklar var
parseInt("09", 10)
Bazı durumlarda, sayının dize temsili bilimsel bir gösterim olabilir, bu durumda parseInt yanlış bir sonuç üretecektir.
parseInt(100000000000000000000000000000000, 10) // 1e+32
Bu çağrı sonuç olarak 1 üretecektir.
parseInt
mümkün olduğunca kaçınılmalıdır. Douglas Crockford'un uyarısı şöyledir: "Dizenin ilk karakteri 0 ise, dize taban 10 yerine taban 8'de değerlendirilir. Taban 8, 8 ve 9'da rakamlar olmadığından parseInt (" 08 ") ve parseInt ("09") sonuç olarak 0 üretir.Bu hata, tarihleri ve saatleri ayrıştıran programlarda sorunlara neden olur Neyse ki, parseInt bir radix parametresi alabilir, böylece parseInt ("08", 10) 8 üretir. radix parametresini girin. " archive.oreilly.com/pub/a/javascript/excerpts/…
parseInt
Kaçınılması gerektiğini söylemez ; sadece farkında olmanız gereken bazı şeyler var. Bunların farkında olmalı ve başa çıkmaya hazır olmalısınız.
parseInt
bir sayı argümanı ile çağırma . parseInt
kısmi sayı dizelerini ayrıştırmalı, kesik sayıları değil.
JavaScript, negatif sayıların tabanını ve tamsayı olmayan sayıların kalanını hesaplar ve matematiksel tanımları izler.
FLOOR, "parametreden daha küçük en büyük tam sayı" olarak tanımlanır, bu nedenle:
HATIRLATMA, bir bölümün (Öklid aritmetiği) "geride bırakılması" olarak tanımlanır. Temettü bir tamsayı olmadığında, bölüm genellikle bir tamsayı değildir, yani, kalan yoktur, ancak bölüm bir tamsayı olmaya zorlanırsa (ve birisi bir kişinin kalanını veya modülünü almaya çalıştığında bu olur kayan nokta sayısı), açık bir şekilde tamsayı olmayan bir "kalan" olacaktır.
JavaScript her şeyi beklendiği gibi hesaplar, bu nedenle programcı doğru soruları sormaya dikkat etmelidir (ve insanlar sorulan soruları cevaplamaya dikkat etmelidir!) Yarin'in ilk sorusu "X'in Y'nin tamsayı bölümü nedir" DEĞİLDİR, ancak, bunun yerine, "belirli bir tamsayının bir başkasına GİRİŞ sayısı". Pozitif sayılar için, cevap her ikisi için de aynıdır, ancak negatif sayılar için aynı değildir, çünkü tamsayı bölümü (bölenle temettü), bir sayının (bölen) "diğerine" (temettü) "gittiği zamandan -1 daha küçük olacaktır. Başka bir deyişle, FLOOR negatif bir sayının tamsayı bölümü için doğru cevabı döndürecektir, ancak Yarin bunu sormadı!
gammax doğru cevap verdi, bu kod Yarin tarafından istendiği gibi çalışıyor. Öte yandan Samuel yanılıyor, matematik yapmadı, sanırım ya da işe yaradığını görürdü (ayrıca, örneğinin böleninin ne olduğunu söylemedi, ama umarım öyleydi 3):
Kalan = X% Y = -100% 3 = -1
= (X - Kalan) / Y = (-100 - -1) / 3 = -99 / 3 = -33
Bu arada, Firefox 27.0.1'deki kodu test ettim, beklendiği gibi pozitif ve negatif sayılarla ve hem temettü hem de bölen için tamsayı olmayan değerlerle çalıştı. Misal:
-100.34 / 3.57: Gidiyor = -28, Kalan = -0.3800000000000079
Evet, fark ettim, orada hassas bir sorun var, ama kontrol etmek için zamanım olmadı (Firefox, Windows 7 veya CPU'mun FPU'su ile ilgili bir sorun olup olmadığını bilmiyorum). Ancak Yarin'in sadece tamsayıları içeren sorusu için gammax'ın kodu mükemmel çalışıyor.
Sayfa sayısını hesaplama tek bir adımda yapılabilir: Math.ceil (x / y)
Alex Moore-Niemi'nin bir cevap olarak yorumu:
Burada arama yapan Google'dan Rubyistler için divmod
bunu şu şekilde uygulayabilirsiniz:
function divmod(x, y) {
var div = Math.trunc(x/y);
var rem = x % y;
return [div, rem];
}
Sonuç:
// [2, 33]
divmod
kullanımları bölümü (katlı Math.floor
(kesik bölünmesinden farklıdır), Math.trunc
) negatif sayılar katılmaktadırlar. Bu, NPM divmod
paketi , Rubydivmod
, SWI-Prologdivmod
ve muhtemelen diğer birçok uygulama için de geçerlidir.
divmod
iki işlemi ayrı ayrı hesaplamaktan iki kat daha hızlı gerçekleştirildiğinden emin olun. Bu performans avantajı olmadan böyle bir işlevin sağlanması kafa karıştırıcı olabilir.
Sadece iki güçle bölüyorsanız, bitsel operatörleri kullanabilirsiniz:
export function divideBy2(num) {
return [num >> 1, num & 1];
}
export function divideBy4(num) {
return [num >> 2, num & 3];
}
export function divideBy8(num) {
return [num >> 3, num & 7];
}
(Birincisi bölüm, ikincisi kalan)
function divideByPowerOf2(num, exponent) { return [num >> exponent, num & ((1 << exponent) - 1)]; }
,.
Bu her zaman sıfıra doğru kesilir. Çok geç olup olmadığından emin değilim, ama işte gidiyor:
function intdiv(dividend, divisor) {
divisor = divisor - divisor % 1;
if (divisor == 0) throw new Error("division by zero");
dividend = dividend - dividend % 1;
var rem = dividend % divisor;
return {
remainder: rem,
quotient: (dividend - rem) / divisor
};
}
JS çalışma zamanının böyle gösteremediği çok büyük tamsayıların kalanını hesaplamanız gerekiyorsa (2 ^ 32'den büyük herhangi bir tam sayı bir kayan nokta olarak gösterilir ve bu nedenle kesinlik kaybeder), biraz hile yapmanız gerekir.
Bu, günlük hayatımızın birçok örneğinde (banka hesap numaraları, kredi kartları, ...) bulunan birçok kontrol basamağı durumunu kontrol etmek için özellikle önemlidir.
Her şeyden önce numaranızı bir dize olarak ihtiyacınız var (aksi takdirde zaten kesinlik kaybettiniz ve geri kalanı mantıklı değil).
str = '123456789123456789123456789'
Artık dizenizi, daha küçük parçalara ayırmanız gerekir, böylece kalanların ve bir dizenin birleştirilmesi 9 haneye sığabilir.
digits = 9 - String(divisor).length
Dizeyi bölmek için normal bir ifade hazırlama
splitter = new RegExp(`.{1,${digits}}(?=(.{${digits}})+$)`, 'g')
Örneğin digits
, 7 ise normal ifade
/.{1,7}(?=(.{7})+$)/g
Maksimum uzunluğu 7 olan boş olmayan bir alt dize ile eşleşir (bunu (?=...)
pozitif bir ileriye doğru) ve 7'den daha fazla sayıda karakter takip eder. 'G' ifadesi, ilk eşleşmede durmadan tüm dizgiden geçmesini sağlamaktır.
Şimdi her bir parçayı tamsayıya dönüştürün ve kalanları hesaplayın reduce
(önceki geri kalanı - veya 0 - 10'un doğru gücüyle çarparak):
reducer = (rem, piece) => (rem * Math.pow(10, digits) + piece) % divisor
Bu, "çıkarma" kalan algoritması nedeniyle çalışacaktır:
n mod d = (n - kd) mod d
bu, son sayıyı etkilemeden bir sayının ondalık gösteriminin herhangi bir 'başlangıç kısmının' geri kalanı ile değiştirilmesine izin verir.
Son kod şöyle görünecektir:
function remainder(num, div) {
const digits = 9 - String(div).length;
const splitter = new RegExp(`.{1,${digits}}(?=(.{${digits}})+$)`, 'g');
const mult = Math.pow(10, digits);
const reducer = (rem, piece) => (rem * mult + piece) % div;
return str.match(splitter).map(Number).reduce(reducer, 0);
}
3.5 % 2
1.5 olarak değerlendirilir. Gerektiğinde