Risposte:
Per alcuni numeri y
e alcuni divisori, x
calcolare il quoziente ( quotient
) e il resto ( remainder
) come:
var quotient = Math.floor(y/x);
var remainder = y % x;
floor
e %
insieme non sono coerenti in questo modo. Utilizzare trunc
invece di floor
(consentendo in tal modo i resti negativi) o utilizzare la sottrazione per ottenere il resto ( rem = y - div * x
).
rem
in ogni caso, è possibile ottenere il quoziente div
più velocemente senza pavimentazione: (y - rem) / x
. 2. A proposito dell'operazione modulo secondo la definizione raccomandata da Donald Knuth (segno-fiammifero-divisore, non il resto cioè modulo euclideo, né il segno-fiammifero-segno dividendo di JavaScript) è ciò che possiamo codificare in JavaScript come function mod (a, n) { return a % n + (Math.sign(a) !== Math.sign(n) ? n : 0); }
.
Non sono un esperto di operatori bit a bit, ma ecco un altro modo per ottenere l'intero numero:
var num = ~~(a / b);
Questo funzionerà correttamente anche per i numeri negativi, mentre Math.floor()
arrotonderà nella direzione sbagliata.
Anche questo sembra corretto:
var num = (a / b) >> 0;
a/b | 0
~~int
, int | 0
E int >> 0
non modifica argomento iniziale, ma far passare interprete parte integrante all'operatore.
floor
difficilmente gira nella direzione sbagliata, dato il suo nome, ma non la direzione che la gente generalmente vuole però!
a = 12447132275286670000; b = 128
Math.floor(a/b)
-> 97243220900677100
e ~~(a/b)
-> -1231452688
.
~~(5/2) --> 2
come fa (5/2)>>0 --> 2
, ma ~~(5/2) + 1 --> 3
, mentre ~~(5/2)>>0 + 1 --> 1
. ~~
è una buona scelta perché la precedenza è più appropriata.
Ho fatto alcuni test di velocità su Firefox.
-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
Quanto sopra si basa su 10 milioni di prove per ciascuno.
Conclusione: utilizzare (a/b>>0)
(o (~~(a/b))
o (a/b|0)
) per ottenere circa il 20% di guadagno in termini di efficienza. Inoltre, tieni presente che sono tutti incompatibili con Math.floor
, quando a/b<0 && a%b!=0
.
Math.floor
e chissà quante altre funzioni API, o conoscere l' ~
operatore (bit a bit) e come funzionano le operazioni bit a bit in JS e quindi comprendere l'effetto della doppia tilde?
Math.floor
meglio. E anche se no, questo è googleable.
ES6 introduce il nuovo Math.trunc
metodo. Ciò consente di correggere la risposta di @ MarkElliot per farlo funzionare anche con numeri negativi:
var div = Math.trunc(y/x);
var rem = y % x;
Si noti che i Math
metodi hanno il vantaggio rispetto agli operatori bit a bit di lavorare con numeri oltre 2 31 .
18014398509481984 == 18014398509481985
,.
~~(x/y)
. Hai bisogno di supportare numeri più grandi fino a 54 bit firmati? Usa Math.trunc
se ce l'hai, o Math.floor
altrimenti (corretto per i numeri negativi). Hai bisogno di supportare numeri ancora più grandi? Usa una libreria di grandi numeri.
divmod
, puoi implementarlo come tale: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
:). Ho controllato con 100,3; -100,3; 100, -3 e -100, -3. Certo, è passato molto tempo dal tuo commento e le cose cambiano.
Di solito uso:
const quotient = (a - a % b) / b;
const remainder = a % b;
Probabilmente non è il più elegante, ma funziona.
È possibile utilizzare la funzione parseInt
per ottenere un risultato troncato.
parseInt(a/b)
Per ottenere un resto, usa l'operatore mod:
a%b
parseInt ha alcune insidie con stringhe, per evitare l'uso del parametro radix con base 10
parseInt("09", 10)
In alcuni casi la rappresentazione in forma di stringa del numero può essere una notazione scientifica, in questo caso parseInt produrrà un risultato errato.
parseInt(100000000000000000000000000000000, 10) // 1e+32
Questa chiamata produrrà 1 come risultato.
parseInt
dovrebbe essere evitato quando possibile. Ecco l'avvertimento di Douglas Crockford: "Se il primo carattere della stringa è 0, la stringa viene valutata nella base 8 anziché nella base 10. Nella base 8, 8 e 9 non sono cifre, quindi parseInt (" 08 ") e parseInt ("09") produce 0 come risultato. Questo errore causa problemi nei programmi che analizzano date e ore. Fortunatamente, parseInt può prendere un parametro radix, in modo che parseInt ("08", 10) produca 8. Ti consiglio sempre fornire il parametro radix. " archive.oreilly.com/pub/a/javascript/excerpts/…
parseInt
dovrebbe essere evitato; solo che ci sono alcuni aspetti da tenere presente. Devi essere consapevole di queste cose ed essere pronto a far fronte.
parseInt
con un argomento numerico. parseInt
dovrebbe analizzare stringhe parzialmente numeriche, non troncare i numeri.
JavaScript calcola il pavimento dei numeri negativi e il resto dei numeri non interi, seguendo le definizioni matematiche per essi.
FLOOR è definito come "il numero intero più grande più piccolo del parametro", quindi:
REMAINDER è definito come il "residuo" di una divisione (aritmetica euclidea). Quando il dividendo non è un numero intero, di solito anche il quoziente non è un numero intero, ovvero non vi è alcun resto, ma se il quoziente è costretto a essere un numero intero (ed è quello che succede quando qualcuno cerca di ottenere il resto o il modulo di un numero in virgola mobile), ci sarà un "numero intero" non intero, ovviamente.
JavaScript calcola tutto come previsto, quindi il programmatore deve fare attenzione a porre le domande giuste (e le persone dovrebbero fare attenzione a rispondere a ciò che viene chiesto!) La prima domanda di Yarin NON era "qual è la divisione intera di X per Y", ma, invece "TUTTO il numero di volte in cui un dato intero VA IN UN altro". Per i numeri positivi, la risposta è la stessa per entrambi, ma non per i numeri negativi, perché la divisione intera (dividendo per divisore) sarà -1 più piccola delle volte in cui un numero (divisore) "entra" in un altro (dividendo). In altre parole, FLOOR restituirà la risposta corretta per una divisione intera di un numero negativo, ma Yarin non l'ha chiesto!
gammax ha risposto correttamente, quel codice funziona come richiesto da Yarin. D'altra parte, Samuel ha torto, non ha fatto la matematica, immagino, o avrebbe visto che funziona (inoltre, non ha detto quale fosse il divisore del suo esempio, ma spero che lo fosse 3):
Resto = X% Y = -100% 3 = -1
GoesInto = (X - Resto) / Y = (-100 - -1) / 3 = -99 / 3 = -33
A proposito, ho testato il codice su Firefox 27.0.1, ha funzionato come previsto, con numeri positivi e negativi e anche con valori non interi, sia per i dividendi che per i divisori. Esempio:
-100.34 / 3.57: va in = -28, resto = -0.3800000000000079
Sì, ho notato, c'è un problema di precisione lì, ma non ho avuto il tempo di controllarlo (non so se si tratta di un problema con Firefox, Windows 7 o con la FPU della mia CPU). Per la domanda di Yarin, tuttavia, che coinvolge solo numeri interi, il codice gammax funziona perfettamente.
Math.floor(operation)
restituisce il valore arrotondato per difetto dell'operazione.
Esempio di 1 ° domanda:
var x = 5;
var y = 10.4;
var z = Math.floor(x + y);
console.log(z);
Console:
15
Esempio di seconda domanda:
var x = 14;
var y = 5;
var z = Math.floor(x%y);
console.log(x);
Console:
4
Il calcolo del numero di pagine può essere eseguito in un solo passaggio: Math.ceil (x / y)
Il commento di Alex Moore-Niemi come risposta:
Per i rubyisti qui da Google in cerca di divmod
, puoi implementarlo come tale:
function divmod(x, y) {
var div = Math.trunc(x/y);
var rem = x % y;
return [div, rem];
}
Risultato:
// [2, 33]
divmod
utilizza la divisione floored ( Math.floor
), che differisce dalla divisione troncata ( Math.trunc
) quando sono coinvolti numeri negativi. Questo è il caso del pacchetto NPMdivmod
, Rubydivmod
, SWI-Prologdivmod
e probabilmente anche molte altre implementazioni.
divmod
esiste perché è due volte più veloce rispetto al calcolo separato delle due operazioni. Fornire una tale funzione senza questo vantaggio prestazionale potrebbe essere fonte di confusione.
Se stai solo dividendo con potenze di due, puoi usare operatori bit a bit:
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];
}
(Il primo è il quoziente, il secondo il resto)
function divideByPowerOf2(num, exponent) { return [num >> exponent, num & ((1 << exponent) - 1)]; }
.
Questo troncerà sempre verso zero. Non sono sicuro che sia troppo tardi, ma qui va:
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
};
}
Se devi calcolare il resto per numeri interi molto grandi, che il runtime JS non può rappresentare come tale (qualsiasi numero intero maggiore di 2 ^ 32 è rappresentato come un float e quindi perde precisione), devi fare qualche trucco.
Ciò è particolarmente importante per controllare molti casi di cifre di controllo che sono presenti in molti casi della nostra vita quotidiana (numeri di conto bancario, carte di credito, ...)
Prima di tutto hai bisogno del tuo numero come stringa (altrimenti hai già perso la precisione e il resto non ha senso).
str = '123456789123456789123456789'
Ora è necessario dividere la stringa in parti più piccole, abbastanza piccole da consentire la concatenazione di qualsiasi resto e un pezzo di stringa in 9 cifre.
digits = 9 - String(divisor).length
Prepara un'espressione regolare per dividere la stringa
splitter = new RegExp(`.{1,${digits}}(?=(.{${digits}})+$)`, 'g')
Ad esempio, se digits
è 7, regexp è
/.{1,7}(?=(.{7})+$)/g
Corrisponde a una sottostringa non vuota di lunghezza massima 7, che è seguita ( (?=...)
è un punto di vista positivo) da un numero di caratteri che è multiplo di 7. La 'g' è di far scorrere l'espressione attraverso tutta la stringa, senza fermarsi alla prima corrispondenza.
Ora converti ogni parte in numero intero e calcola i resti per reduce
(aggiungendo nuovamente il resto precedente - o 0 - moltiplicato per la potenza corretta di 10):
reducer = (rem, piece) => (rem * Math.pow(10, digits) + piece) % divisor
Questo funzionerà a causa dell'algoritmo di resto "sottrazione":
n mod d = (n - kd) mod d
che consente di sostituire qualsiasi "parte iniziale" della rappresentazione decimale di un numero con il suo resto, senza influire sul resto finale.
Il codice finale sarebbe simile a:
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
valuta 1.5. Assicurati di gestire (analisi, piano, ecc.) Come richiesto