JavaScript% (modulo) negatif sayılar için negatif sonuç verir


253

Göre Google Hesap (-13) % 64 olduğunu 51.

Javascript'e göre (bakınız bu JSBin ) -13.

Bunu nasıl düzeltirim?


Bu sadece bir öncelik meselesi olabilir. Şunu musunuz (-13) % 64yoksa -(13 % 64)? Şahsen, ben sadece ekstra netlik için, her iki şekilde de parens koymak istiyorum.
MatrixFrog

2
esasen birinin kopyası nasıl negatif sayılar ile modül hesaplamaları yapmak java yapar? bu bir javascript sorusu olmasına rağmen.
Başkan James K. Polk

85
Javascript bazen çok acımasız bir şaka gibi hissediyor
dukeofgaming

6
google yanlış olamaz
caub

10
Temel problem JS'de %modulo operatörü değildir. Kalan operatör. JavaScript'te modulo operatörü yok. Bu yüzden kabul edilen cevap yoludur.
Redu

Yanıtlar:


263
Number.prototype.mod = function(n) {
    return ((this%n)+n)%n;
};

Bu makaleden alınmıştır: JavaScript Modulo Hatası


23
Buna "böcek" diyeceđimi bilmiyorum. Modulo işlemi negatif sayılar üzerinde çok iyi tanımlanmamıştır ve farklı bilgi işlem ortamları bunu farklı şekilde ele alır. Wikipedia'nın modulo işlemi ile ilgili makalesi oldukça iyi bir şekilde ele alıyor.
Daniel Pryden

22
Sıklıkla 'modulo' olarak adlandırıldığı için aptal gibi görünebilir, bu da matematik tanımıyla aynı davranacağını gösterir (bkz. ℤ / nℤ cebiri), öyle değil.
etienne

7
N'yi eklemeden önce neden modulo almalıyım? Neden sadece n'yi ekleyip modulo almıyorsunuz?
starwed

12
@starwed bu% n'yi kullanmadıysanız başarısız olur x < -n- örneğin (-7 + 5) % 5 === -2ama ((-7 % 5) + 5) % 5 == 3.
fadedbee

7
Bu işleve erişmek için -13% 10 yerine (-13) .mod (10) biçimini kullanması gerektiği cevabını eklemenizi tavsiye ederim.
Jp_

161

Kullanımı Number.prototypeher zaman size sayı sarılır prototip yöntemi kullanmak çünkü YAVAŞ olduğunu Object. Bunun yerine:

Number.prototype.mod = function(n) {
  return ((this % n) + n) % n;
}

kullanın:

function mod(n, m) {
  return ((n % m) + m) % m;
}

Bkz. Http://jsperf.com/negative-modulo/2

Prototip kullanmaya göre ~% 97 daha hızlı. Performans elbette sizin için önemliyse ..


1
Harika bir ipucu. Jsperf'inizi aldım ve bu sorudaki çözümlerin geri kalanıyla karşılaştırdım (ancak bu yine de en iyisi gibi görünüyor): jsperf.com/negative-modulo/3
Mariano Desanze

11
Mikro optimizasyonu. Bunun için herhangi bir fark yaratmak için muazzam miktarda mod hesaplaması yapmanız gerekir. En net ve en sürdürülebilir olanı kodlayın, ardından aşağıdaki performans analizini optimize edin.
ChrisV

Ben senin var düşünmek ns ve mikinci örnek @StuR yanlış bir yol etrafında s. Olmalı return ((n % m) + m) % m;.
vimist

Bu, kendisinin yanıtı değil, kabul edilen cevaba bir yorum olmalıdır.
xehpuk

5
Bu cevapta belirtilen motivasyon bir mikro optimizasyon, evet, ancak prototipi değiştirmek sorunlu. En az yan etki ile yaklaşımı tercih edin, bu da budur.
Keen

31

%JavaScript operatör kalan operatör değil, modülo operatörü (ana fark nasıl muamele negatif sayılar olan) olduğu:

-1 % 8 // -1, not 7


8
Bu gerektiğini kalan operatör çağrılacak ancak edilir modülü operatörü denir: developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/...
Büyük McLargeHuge

16
@DaveKennedy: MDN resmi bir dil referansı değil, bazen yanlış yapan topluluk tarafından düzenlenen bir sitedir. Spec ona bir modulo operatörü demiyor ve söyleyebildiğim kadarıyla hiç sahip değil (ES3'e geri döndüm). Açıkça belirtilir ki, operatör zımni bir bölümün geri kalanını verir ve bunu "% operatörü" olarak adlandırır.
TJ Crowder

2
Eğer çağrılırsa remainder, tanım olarak 0'dan büyük olmalıdır. Liseden bölünme teoremini hatırlamıyor musunuz ?! Belki burada bir göz atabilirsiniz: en.wikipedia.org/wiki/Euclidean_division
Ahmad

19

Olumlu bir sonuç döndürmek için bir "mod" işlevi.

var mod = function (n, m) {
    var remain = n % m;
    return Math.floor(remain >= 0 ? remain : remain + m);
};
mod(5,22)   // 5
mod(25,22)  // 3
mod(-1,22)  // 21
mod(-2,22)  // 20
mod(0,22)   // 0
mod(-1,22)  // 21
mod(-21,22) // 1

Ve tabi ki

mod(-13,64) // 51

1
MDN resmi bir dil referansı değildir, bazen yanlış yapan topluluk tarafından düzenlenen bir sitedir. Spec ona bir modulo operatörü demiyor ve söyleyebildiğim kadarıyla hiç sahip değil (ES3'e geri döndüm). Açıkça belirtilir ki, operatör zımni bir bölümün geri kalanını verir ve bunu "% operatörü" olarak adlandırır.
TJ Crowder

1
Hata! Belirttiğiniz bağlantı aslında #sec-applying-the-mod-operatorurl'de referans veriyor :) Her neyse, not için teşekkürler, tüylerimi cevabımdan çıkardım, yine de gerçekten önemli değil.
Shanimal

3
@ Shanimal: LOL! Öyle. HTML düzenleyicisi tarafından bir hata. Teknik özellik metni değil.
TJ Crowder

10

Kabul edilen cevap beni biraz tedirgin ediyor çünkü% operatörünü yeniden kullanıyor. Javascript gelecekte davranışı değiştirirse ne olur?

% Yeniden kullanmayan bir geçici çözüm aşağıdadır:

function mod(a, n) {
    return a - (n * Math.floor(a/n));
}

mod(1,64); // 1
mod(63,64); // 63
mod(64,64); // 0
mod(65,64); // 1
mod(0,64); // 0
mod(-1,64); // 63
mod(-13,64); // 51
mod(-63,64); // 1
mod(-64,64); // 0
mod(-65,64); // 63

8
Javascript modulo operatörünü matematiksel tanımla eşleşecek şekilde değiştirdiyse, kabul edilen cevap yine de işe yarayacaktır.
starwed

20
"Ya Javascript gelecekte davranışı değiştirirse?" - Neden olsun ki? Böyle temel bir operatörün davranışını değiştirmek olası değildir.
nnnnnn

1
Bu cevabı ve alternatifi # answer-4467559 ve 4 nedenden dolayı cevabı paylaşmak için +1 : (1) Neden belirtiyor & evet “Böyle temel bir op'in davranışını değiştirmek olası değildir”, ancak yine de düşünmeye ihtiyatlı bulmak bile gerekmiyor. (2) çalışan bir op'u kırık bir açıdan tanımlamak, etkileyici olsa da, en azından 1. bakışta endişe verici, (3) bu alternatifi iyi doğruladığımda, takip etmeyi daha kolay buluyorum Hızlı bakış. (4) minik: 2 (mod) div yerine 1 div + 1 mul kullanır ve iyi bir FPU olmadan ÇOK daha önceki donanımlarda duydum, çarpma daha hızlıydı.
Destiny Architect

2
@DestinyArchitect ihtiyatlı değil, anlamsız. Kalan operatörün davranışını değiştirecek olsaydı, onu kullanan iyi bir program aralığını kıracaktır. Bu asla olmayacak.
Aegis

10
Ne davranışı eğer -, *, /, ;, ., (, ), ,, Math.floor, functionveya returndeğişikliklerin? O zaman kodunuz çok bozuk.
xehpuk

5

Beklediğiniz gibi davranmasa da, JavaScript'in 'davranış' olmadığı anlamına gelmez. Modulo hesaplaması için yapılmış bir JavaScript seçimidir. Çünkü, tanım gereği her iki cevap da mantıklıdır.

Bunu Wikipedia'dan görün . Sağda, farklı dillerin sonucun işaretini nasıl seçtiğini görebilirsiniz.


4

Eğer xbir tam sayı ve n2 gücü ise, x & (n - 1)yerine kullanabilirsiniz x % n.

> -13 & (64 - 1)
51 

2

Görünüşe göre dereceler etrafında mod değiştirmeye çalışıyorsanız (-50 dereceniz - 200 dereceniz varsa) gibi bir şey kullanmak istersiniz:

function modrad(m) {
    return ((((180+m) % 360) + 360) % 360)-180;
}

1

Negatif a ve negatif n ile de ilgileniyorum

 //best perf, hard to read
   function modul3(a,n){
        r = a/n | 0 ;
        if(a < 0){ 
            r += n < 0 ? 1 : -1
        }
        return a - n * r 
    }
    // shorter code
    function modul(a,n){
        return  a%n + (a < 0 && Math.abs(n)); 
    }

    //beetween perf and small code
    function modul(a,n){
        return a - n * Math[n > 0 ? 'floor' : 'ceil'](a/n); 
    }

1

Bu bir hata değil, modulo hesaplamak için 3 fonksiyon var, ihtiyaçlarınıza uyan olanı kullanabilirsiniz (Öklid fonksiyonunu kullanmanızı tavsiye ederim)

Ondalık parça işlevini kesme

console.log(  41 %  7 ); //  6
console.log( -41 %  7 ); // -6
console.log( -41 % -7 ); // -6
console.log(  41 % -7 ); //  6

Tam sayı parça fonksiyonu

Number.prototype.mod = function(n) {
    return ((this%n)+n)%n;
};

console.log( parseInt( 41).mod( 7) ); //  6
console.log( parseInt(-41).mod( 7) ); //  1
console.log( parseInt(-41).mod(-7) ); // -6
console.log( parseInt( 41).mod(-7) ); // -1

Öklid işlevi

Number.prototype.mod = function(n) {
    var m = ((this%n)+n)%n;
    return m < 0 ? m + Math.abs(n) : m;
};

console.log( parseInt( 41).mod( 7) ); // 6
console.log( parseInt(-41).mod( 7) ); // 1
console.log( parseInt(-41).mod(-7) ); // 1
console.log( parseInt( 41).mod(-7) ); // 6

1
Öklid işlevinde m <0 kontrolü işe yaramaz çünkü ((bu% n) + n)% n her zaman pozitiftir
bormat

1
@bormat Evet, ama Javascript %negatif sonuçlar döndürebilir (bu bu fonksiyonların amacı, düzeltmek için)
zessx

bu kodu yazdınız. Number.prototype.mod = function (n) {var m = ((bu% n) + n)% n; dönüş m <0? m + Math.abs (n): m; }; [/ code] bana m'nin nigatif olduğu bir n değeri verir. n'nin değeri yoktur, burada m negatiftir, çünkü ilk% 'den sonra n eklersiniz.
bormat

Bu kontrol olmadan, yerine parseInt(-41).mod(-7)dönecekti (ve bu tam olarak yazdığım Tamsayı parçası işlevinin -61
amacıdır

1
İkinci modulo sayısını kaldırarak işlevinizi basitleştirebilirsiniz Number.prototype.mod = function (n) {var m = this% n; dönüş (m <0)? m + Math.abs (n): m; };
bormat

0

İşi sizin için yapacak bir NPM paketi var. Aşağıdaki komutla kurabilirsiniz.

npm install just-modulo --save

Kullanım README'den kopyalandı

import modulo from 'just-modulo';

modulo(7, 5); // 2
modulo(17, 23); // 17
modulo(16.2, 3.8); // 17
modulo(5.8, 3.4); //2.4
modulo(4, 0); // 4
modulo(-7, 5); // 3
modulo(-2, 15); // 13
modulo(-5.8, 3.4); // 1
modulo(12, -1); // NaN
modulo(-3, -8); // NaN
modulo(12, 'apple'); // NaN
modulo('bee', 9); // NaN
modulo(null, undefined); // NaN

GitHub deposunu aşağıdaki bağlantıdan bulabilirsiniz:

https://github.com/angus-c/just/tree/master/packages/number-modulo

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.