Jawaban:
Untuk beberapa nomor y
dan beberapa pembagi x
menghitung hasil bagi ( quotient
) dan sisanya ( remainder
) sebagai:
var quotient = Math.floor(y/x);
var remainder = y % x;
floor
dan %
bersama - sama tidak konsisten dengan cara itu. Baik gunakan trunc
alih-alih floor
(dengan demikian mengizinkan sisa negatif) atau gunakan pengurangan untuk mendapatkan sisanya ( rem = y - div * x
).
rem
pula, Anda bisa mendapatkan hasil bagi div
lebih cepat tanpa lantai: (y - rem) / x
. 2. Ngomong-ngomong operasi modulo oleh definisi yang direkomendasikan Donald Knuth (tanda-cocok-divisor, bukan sisanya yaitu modulus Euclidean, atau JavaScript tanda-cocok-dividen) adalah apa yang bisa kita kode dalam JavaScript sebagai function mod (a, n) { return a % n + (Math.sign(a) !== Math.sign(n) ? n : 0); }
.
Saya bukan ahli dalam operator bitwise, tapi inilah cara lain untuk mendapatkan seluruh nomor:
var num = ~~(a / b);
Ini akan bekerja dengan baik untuk angka negatif juga, sementara Math.floor()
akan membulatkan arah yang salah.
Ini tampaknya benar juga:
var num = (a / b) >> 0;
a/b | 0
~~int
, int | 0
dan int >> 0
tidak mengubah argumen awal, tetapi menjadikan interpreter pass sebagai bagian integral dari operator.
floor
hampir tidak berputar ke arah yang salah, diberi nama - hanya saja bukan arah yang umumnya orang inginkan!
a = 12447132275286670000; b = 128
Math.floor(a/b)
-> 97243220900677100
dan ~~(a/b)
-> -1231452688
.
~~(5/2) --> 2
seperti halnya (5/2)>>0 --> 2
, tapi ~~(5/2) + 1 --> 3
, sementara ~~(5/2)>>0 + 1 --> 1
. ~~
adalah pilihan yang baik karena diutamakan lebih tepat.
Saya melakukan beberapa tes kecepatan di 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
Di atas didasarkan pada 10 juta percobaan untuk masing-masing.
Kesimpulan: Gunakan (a/b>>0)
(atau (~~(a/b))
atau (a/b|0)
) untuk mencapai efisiensi sekitar 20%. Juga perlu diingat bahwa mereka semua tidak konsisten dengan Math.floor
, kapan a/b<0 && a%b!=0
.
Math.floor
dan siapa-tahu-berapa-banyak fungsi API lainnya, atau belajar tentang ~
operator (bitwise-not) dan bagaimana operasi bitwise bekerja di JS dan kemudian memahami efek double tilde?
Math.floor
lebih mengerti . Dan kalaupun tidak, yang ini bisa di-googleable.
ES6 memperkenalkan Math.trunc
metode baru . Ini memungkinkan untuk memperbaiki jawaban @ MarkElliot untuk membuatnya berfungsi untuk angka negatif juga:
var div = Math.trunc(y/x);
var rem = y % x;
Perhatikan bahwa Math
metode memiliki keunggulan dibandingkan operator bitwise yang mereka gunakan dengan angka di atas 2 31 .
18014398509481984 == 18014398509481985
,.
~~(x/y)
. Perlu mendukung jumlah yang lebih besar hingga 54 bit yang ditandatangani? Gunakan Math.trunc
jika Anda memilikinya, atau Math.floor
sebaliknya (koreksi untuk angka negatif). Perlu mendukung jumlah yang lebih besar lagi? Gunakan beberapa perpustakaan angka besar.
divmod
, Anda dapat menerapkannya seperti: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
:). Saya memeriksa dengan 100,3; -100,3; 100, -3 dan -100, -3. Tentu saja, banyak waktu telah berlalu sejak komentar Anda dan banyak hal berubah.
Saya biasanya menggunakan:
const quotient = (a - a % b) / b;
const remainder = a % b;
Ini mungkin bukan yang paling elegan, tetapi berhasil.
Anda dapat menggunakan fungsi ini parseInt
untuk mendapatkan hasil yang terpotong.
parseInt(a/b)
Untuk mendapatkan sisanya, gunakan mod operator:
a%b
parseInt memiliki beberapa perangkap dengan string, untuk menghindari penggunaan parameter radix dengan basis 10
parseInt("09", 10)
Dalam beberapa kasus representasi string nomor dapat menjadi notasi ilmiah, dalam hal ini, parseInt akan menghasilkan hasil yang salah.
parseInt(100000000000000000000000000000000, 10) // 1e+32
Panggilan ini akan menghasilkan 1 sebagai hasilnya.
parseInt
harus dihindari bila memungkinkan. Berikut ini peringatan Douglas Crockford: "Jika karakter pertama dari string adalah 0, maka string tersebut dievaluasi dalam basis 8, bukan basis 10. Dalam basis 8, 8 dan 9 bukan digit, jadi parseInt (" 08 ") dan parseInt ("09") menghasilkan 0 sebagai hasilnya. Kesalahan ini menyebabkan masalah dalam program yang menguraikan tanggal dan waktu. Untungnya, parseInt dapat mengambil parameter radix, sehingga parseInt ("08", 10) menghasilkan 8. Saya sarankan Anda selalu berikan parameter radix. " archive.oreilly.com/pub/a/javascript/excerpts/…
parseInt
harus dihindari; Hanya saja ada beberapa gotcha yang harus diperhatikan. Anda harus menyadari hal-hal ini dan bersiap untuk mengatasinya.
parseInt
dengan argumen nomor. parseInt
seharusnya mengurai string sebagian-numerik, bukan angka terpotong.
JavaScript menghitung dengan tepat lantai bilangan negatif dan sisa bilangan non-integer, mengikuti definisi matematika untuknya.
LANTAI didefinisikan sebagai "bilangan bulat terbesar yang lebih kecil dari parameter", dengan demikian:
REMAINDER didefinisikan sebagai "sisa" dari suatu divisi (Euclidean arithmetic). Ketika dividen bukan bilangan bulat, hasil bagi biasanya juga bukan bilangan bulat, yaitu, tidak ada sisa, tetapi jika hasil bagi dipaksa menjadi bilangan bulat (dan itulah yang terjadi ketika seseorang mencoba untuk mendapatkan sisa atau modulus dari suatu angka floating-point), akan ada "sisa" non-integer, jelas.
JavaScript memang menghitung semuanya seperti yang diharapkan, sehingga programmer harus berhati-hati untuk mengajukan pertanyaan yang tepat (dan orang-orang harus berhati-hati untuk menjawab apa yang ditanyakan!) Pertanyaan pertama Yarin bukanlah "apa pembagian bilangan X dengan Y", tapi, sebagai gantinya, "SELURUH berapa kali bilangan bulat yang diberikan PERGI ke yang lain". Untuk bilangan positif, jawabannya adalah sama untuk keduanya, tetapi tidak untuk bilangan negatif, karena pembagian bilangan bulat (dividen dengan pembagi) akan -1 lebih kecil daripada kali angka (pembagi) "masuk ke" yang lain (dividen). Dengan kata lain, FLOOR akan mengembalikan jawaban yang benar untuk pembagian bilangan bulat dari angka negatif, tetapi Yarin tidak menanyakan itu!
gammax menjawab dengan benar, kode itu berfungsi seperti yang diminta oleh Yarin. Di sisi lain, Samuel salah, dia tidak menghitung, kurasa, atau dia akan melihat bahwa itu berhasil (juga, dia tidak mengatakan apa yang menjadi pembagi dari teladannya, tetapi saya berharap itu adalah 3):
Sisa = X% Y = -100% 3 = -1
GoesInto = (X - Sisa) / Y = (-100 - -1) / 3 = -99 / 3 = -33
By the way, saya menguji kode pada Firefox 27.0.1, itu berfungsi seperti yang diharapkan, dengan angka positif dan negatif dan juga dengan nilai-nilai non-integer, baik untuk dividen dan pembagi. Contoh:
-100.34 / 3.57: GoesInto = -28, Sisa = -0.380000000000000079
Ya, saya perhatikan, ada masalah presisi di sana, tapi saya tidak punya waktu untuk memeriksanya (saya tidak tahu apakah itu masalah dengan Firefox, Windows 7 atau dengan FPU CPU saya). Namun untuk pertanyaan Yarin, yang hanya melibatkan bilangan bulat, kode gammax berfungsi dengan baik.
Menghitung jumlah halaman dapat dilakukan dalam satu langkah: Math.ceil (x / y)
Komentar Alex Moore-Niemi sebagai jawaban:
Untuk Rubyist di sini dari Google dalam pencarian divmod
, Anda dapat mengimplementasikannya seperti:
function divmod(x, y) {
var div = Math.trunc(x/y);
var rem = x % y;
return [div, rem];
}
Hasil:
// [2, 33]
divmod
menggunakan pembagian lantai ( Math.floor
), yang berbeda dari divisi terpotong ( Math.trunc
) ketika angka negatif terlibat. Ini adalah kasus untuk paket NPMdivmod
, Rubydivmod
, SWI-Prologdivmod
dan mungkin banyak implementasi lainnya juga.
divmod
ada karena ia melakukan dua kali lebih cepat dari komputasi dua operasi secara terpisah. Menyediakan fungsi seperti itu tanpa manfaat kinerja ini mungkin membingungkan.
Jika Anda hanya membagi dengan kekuatan dua, Anda dapat menggunakan operator bitwise:
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];
}
(Yang pertama adalah hasil bagi, yang kedua sisanya)
function divideByPowerOf2(num, exponent) { return [num >> exponent, num & ((1 << exponent) - 1)]; }
,.
Anda dapat menggunakan ternary untuk memutuskan bagaimana menangani nilai integer positif dan negatif juga.
var myInt = (y > 0) ? Math.floor(y/x) : Math.floor(y/x) + 1
Jika angkanya positif, semuanya baik-baik saja. Jika angkanya negatif, itu akan menambah 1 karena cara Math.floor menangani negatif.
Ini akan selalu terpotong menuju nol. Tidak yakin apakah sudah terlambat, tapi begini saja:
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
};
}
Jika Anda perlu menghitung sisanya untuk bilangan bulat yang sangat besar, yang runtime JS tidak dapat wakili seperti itu (bilangan bulat lebih besar dari 2 ^ 32 diwakili sebagai float dan karena itu kehilangan presisi), Anda perlu melakukan beberapa trik.
Ini sangat penting untuk memeriksa banyak kasus digit cek yang ada dalam banyak contoh kehidupan sehari-hari kita (nomor rekening bank, kartu kredit, ...)
Pertama-tama Anda memerlukan nomor Anda sebagai string (jika tidak, Anda telah kehilangan presisi dan sisanya tidak masuk akal).
str = '123456789123456789123456789'
Anda sekarang harus memisahkan string Anda menjadi bagian-bagian yang lebih kecil, cukup kecil sehingga rangkaian sisa dan seutas tali dapat muat dalam 9 digit.
digits = 9 - String(divisor).length
Persiapkan ekspresi reguler untuk memisahkan string
splitter = new RegExp(`.{1,${digits}}(?=(.{${digits}})+$)`, 'g')
Misalnya, jika digits
7, regexp adalah
/.{1,7}(?=(.{7})+$)/g
Ini cocok dengan nonempty substring dengan panjang maksimum 7, yang diikuti ( (?=...)
adalah lookahead positif) oleh sejumlah karakter yang kelipatan dari 7. The 'g' adalah untuk membuat ekspresi dijalankan melalui semua string, tidak berhenti pada pertandingan pertama.
Sekarang konversikan setiap bagian menjadi bilangan bulat, dan hitung sisanya dengan reduce
(menambahkan kembali sisa sebelumnya - atau 0 - dikalikan dengan kekuatan 10 yang benar):
reducer = (rem, piece) => (rem * Math.pow(10, digits) + piece) % divisor
Ini akan berfungsi karena algoritme sisa "pengurangan":
n mod d = (n - kd) mod d
yang memungkinkan untuk mengganti 'bagian awal' dari representasi desimal dari angka dengan sisanya, tanpa mempengaruhi sisa akhir.
Kode akhir akan terlihat seperti:
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
mengevaluasi menjadi 1,5. Pastikan untuk menangani (parseInt, floor, dll.) Seperti yang diperlukan