Câu trả lời:
Đối với một số số y
và một số ước số x
tính thương số ( quotient
) và phần còn lại ( remainder
) là:
var quotient = Math.floor(y/x);
var remainder = y % x;
floor
và %
cùng nhau không nhất quán theo cách đó. Hoặc sử dụng trunc
thay vì floor
(do đó cho phép phần dư âm) hoặc sử dụng phép trừ để lấy phần còn lại ( rem = y - div * x
).
rem
, bạn có thể lấy thương số div
nhanh hơn mà không cần sàn : (y - rem) / x
. 2. Theo cách thức hoạt động modulo theo định nghĩa được đề xuất của Donald Knuth (ký hiệu khớp-ước, không phải là phần còn lại, ví dụ mô-đun Euclide, cũng không phải là mã hóa khớp với ký hiệu JavaScript) là những gì chúng ta có thể viết mã bằng JavaScript function mod (a, n) { return a % n + (Math.sign(a) !== Math.sign(n) ? n : 0); }
.
Tôi không phải là chuyên gia về toán tử bitwise, nhưng đây là một cách khác để lấy toàn bộ số:
var num = ~~(a / b);
Điều này cũng sẽ hoạt động đúng cho các số âm, trong khi Math.floor()
sẽ làm tròn sai hướng.
Điều này có vẻ đúng như là tốt:
var num = (a / b) >> 0;
a/b | 0
~~int
, int | 0
Và int >> 0
không thay đổi lập luận ban đầu, nhưng làm thông dịch viên vượt qua phần không thể thiếu để điều hành.
floor
hầu như không đi sai hướng, được đặt tên - chỉ không phải là hướng mà mọi người thường muốn!
a = 12447132275286670000; b = 128
Math.floor(a/b)
-> 97243220900677100
và ~~(a/b)
-> -1231452688
.
~~(5/2) --> 2
cũng như (5/2)>>0 --> 2
, nhưng ~~(5/2) + 1 --> 3
, trong khi ~~(5/2)>>0 + 1 --> 1
. ~~
là một lựa chọn tốt vì ưu tiên phù hợp hơn.
Tôi đã làm một số bài kiểm tra tốc độ trên 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
Trên đây là dựa trên 10 triệu thử nghiệm cho mỗi.
Kết luận: Sử dụng (a/b>>0)
(hoặc (~~(a/b))
hay (a/b|0)
) để đạt được khoảng 20% tăng hiệu quả. Cũng nên nhớ rằng tất cả chúng không phù hợp với Math.floor
, khi nào a/b<0 && a%b!=0
.
Math.floor
và các chức năng API khác, hoặc tìm hiểu về ~
toán tử (bitwise-not) và cách hoạt động của bitwise trong JS và sau đó hiểu tác dụng của dấu ngã kép?
Math.floor
hơn. Và thậm chí nếu không, cái này là có thể cho phép.
ES6 giới thiệu Math.trunc
phương pháp mới . Điều này cho phép sửa câu trả lời của @ MarkElliot để làm cho nó hoạt động với các số âm:
var div = Math.trunc(y/x);
var rem = y % x;
Lưu ý rằng Math
các phương thức có lợi thế hơn các toán tử bitwise mà chúng hoạt động với các số trên 2 31 .
18014398509481984 == 18014398509481985
.
~~(x/y)
. Cần hỗ trợ số lượng lớn hơn lên đến 54 bit đã ký? Sử dụng Math.trunc
nếu bạn có nó, hoặc Math.floor
nếu không (chính xác cho số âm). Cần hỗ trợ số lượng lớn hơn? Sử dụng một số thư viện số lượng lớn.
divmod
, bạn có thể triển khai nó như sau: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
:). Tôi đã kiểm tra với 100,3; -100,3; 100, -3 và -100, -3. Tất nhiên, rất nhiều thời gian đã trôi qua kể từ khi bình luận của bạn và mọi thứ thay đổi.
Tôi thường sử dụng:
const quotient = (a - a % b) / b;
const remainder = a % b;
Nó có thể không phải là thanh lịch nhất, nhưng nó hoạt động.
Bạn có thể sử dụng hàm parseInt
để có được kết quả rút ngắn.
parseInt(a/b)
Để có phần còn lại, hãy sử dụng toán tử mod:
a%b
parseInt có một số cạm bẫy với chuỗi, để tránh sử dụng tham số cơ số với cơ sở 10
parseInt("09", 10)
Trong một số trường hợp, biểu diễn chuỗi của số có thể là một ký hiệu khoa học, trong trường hợp này, parseInt sẽ tạo ra kết quả sai.
parseInt(100000000000000000000000000000000, 10) // 1e+32
Cuộc gọi này sẽ tạo ra 1 kết quả.
parseInt
nên tránh khi có thể. Dưới đây là cảnh báo của Douglas Crockford: "Nếu ký tự đầu tiên của chuỗi là 0, thì chuỗi được đánh giá ở cơ sở 8 thay vì cơ sở 10. Trong cơ sở 8, 8 và 9 không phải là chữ số, vì vậy parseInt (" 08 ") và parseInt ("09") tạo ra 0 do kết quả của chúng. Lỗi này gây ra sự cố trong các chương trình phân tích ngày và thời gian. May mắn thay, parseInt có thể lấy tham số cơ số, do đó parseInt ("08", 10) tạo ra 8. Tôi khuyên bạn luôn luôn cung cấp thông số cơ số. " archive.oreilly.com/pub/a/javascript/excerpts/ từ
parseInt
nên tránh; chỉ là có một số vấn đề cần chú ý. Bạn phải nhận thức được những điều này và sẵn sàng đối phó.
parseInt
với một đối số số. parseInt
được cho là phân tích các chuỗi số một phần, không cắt các số.
JavaScript tính toán đúng sàn các số âm và phần còn lại của các số không nguyên, theo các định nghĩa toán học cho chúng.
FLOOR được định nghĩa là "số nguyên lớn nhất nhỏ hơn tham số", do đó:
REMAINDER được định nghĩa là "phần còn lại" của một bộ phận (số học Euclide). Khi cổ tức không phải là số nguyên, thương số thường cũng không phải là số nguyên, nghĩa là không có phần còn lại, nhưng nếu thương số buộc phải là số nguyên (và đó là điều xảy ra khi ai đó cố gắng lấy phần còn lại hoặc mô đun của số dấu phẩy động), rõ ràng sẽ có một "số dư" không nguyên.
JavaScript không tính toán mọi thứ như mong đợi, vì vậy, lập trình viên phải cẩn thận đặt câu hỏi thích hợp (và mọi người nên cẩn thận trả lời những gì được hỏi!) Câu hỏi đầu tiên của Yarin KHÔNG phải là "phép chia số nguyên của X cho Y", nhưng, thay vào đó, "số lần WHOLE của một số nguyên đã cho ĐI VÀO một số khác". Đối với các số dương, câu trả lời là giống nhau cho cả hai, nhưng không phải cho các số âm, bởi vì phép chia số nguyên (chia theo số chia) sẽ nhỏ hơn -1 so với số lần (số chia) "đi vào" số khác (cổ tức). Nói cách khác, FLOOR sẽ trả về câu trả lời đúng cho phép chia số nguyên của một số âm, nhưng Yarin đã không hỏi điều đó!
gammax trả lời đúng, mã đó hoạt động theo yêu cầu của Yarin. Mặt khác, Samuel đã sai, tôi đã không làm toán, tôi đoán, hoặc anh ta sẽ thấy rằng nó hoạt động (đồng thời, anh ta đã không nói đâu là ước số của ví dụ của mình, nhưng tôi hy vọng đó là 3):
Phần còn lại = X% Y = -100% 3 = -1
GoesInto = (X - Phần còn lại) / Y = (-100 - -1) / 3 = -99 / 3 = -33
Nhân tiện, tôi đã thử nghiệm mã trên Firefox 27.0.1, nó hoạt động như mong đợi, với các số dương và âm và cả với các giá trị không nguyên, cả về cổ tức và ước số. Thí dụ:
-100.34 / 3.57: GoesInto = -28, phần còn lại = -0.3800000000000079
Vâng, tôi nhận thấy, có một vấn đề chính xác ở đó, nhưng tôi không có thời gian để kiểm tra nó (tôi không biết đó là vấn đề với Firefox, Windows 7 hay với FPU CPU của tôi). Tuy nhiên, đối với câu hỏi của Yarin, chỉ liên quan đến số nguyên, mã của gammax hoạt động hoàn hảo.
Math.floor(operation)
trả về giá trị làm tròn xuống của hoạt động.
Ví dụ về câu hỏi thứ 1 :
var x = 5;
var y = 10.4;
var z = Math.floor(x + y);
console.log(z);
Bảng điều khiển:
15
Ví dụ về câu hỏi thứ 2 :
var x = 14;
var y = 5;
var z = Math.floor(x%y);
console.log(x);
Bảng điều khiển:
4
Tính toán số lượng trang có thể được thực hiện trong một bước: Math.ceil (x / y)
Nhận xét của Alex Moore-Niemi như một câu trả lời:
Đối với Rubyists ở đây từ Google để tìm kiếm divmod
, bạn có thể triển khai nó như sau:
function divmod(x, y) {
var div = Math.trunc(x/y);
var rem = x % y;
return [div, rem];
}
Kết quả:
// [2, 33]
divmod
sử dụng phép chia nổi ( Math.floor
), khác với phép chia ( Math.trunc
) khi các số âm có liên quan. Đây là trường hợp cho gói NPMdivmod
, Rubydivmod
, SWI-Prologdivmod
và có lẽ nhiều triển khai khác nữa.
divmod
tồn tại bởi vì nó thực hiện nhanh gấp đôi so với tính toán hai thao tác riêng biệt. Cung cấp một chức năng như vậy mà không có lợi ích hiệu suất này có thể gây nhầm lẫn.
Nếu bạn chỉ phân chia với quyền hạn của hai, bạn có thể sử dụng các toán tử 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];
}
(Đầu tiên là thương số, thứ hai là phần còn lại)
function divideByPowerOf2(num, exponent) { return [num >> exponent, num & ((1 << exponent) - 1)]; }
.
Điều này sẽ luôn cắt ngắn về không. Không chắc là quá muộn, nhưng ở đây nó đi:
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
};
}
Nếu bạn cần tính toán phần còn lại cho các số nguyên rất lớn, thời gian chạy JS không thể biểu diễn như vậy (bất kỳ số nguyên nào lớn hơn 2 ^ 32 được biểu diễn dưới dạng nổi và do đó mất độ chính xác), bạn cần thực hiện một số mẹo.
Điều này đặc biệt quan trọng để kiểm tra nhiều trường hợp chữ số séc có trong nhiều trường hợp trong cuộc sống hàng ngày của chúng tôi (số tài khoản ngân hàng, thẻ tín dụng, ...)
Trước hết bạn cần số của bạn dưới dạng một chuỗi (nếu không bạn đã mất độ chính xác và phần còn lại không có ý nghĩa).
str = '123456789123456789123456789'
Bây giờ bạn cần chia chuỗi của bạn thành các phần nhỏ hơn, đủ nhỏ để việc nối bất kỳ phần còn lại và một đoạn chuỗi có thể khớp với 9 chữ số.
digits = 9 - String(divisor).length
Chuẩn bị một biểu thức chính quy để tách chuỗi
splitter = new RegExp(`.{1,${digits}}(?=(.{${digits}})+$)`, 'g')
Chẳng hạn, nếu digits
là 7, thì biểu thức chính là
/.{1,7}(?=(.{7})+$)/g
Nó khớp với một chuỗi con không trống có độ dài tối đa 7, được theo sau ( (?=...)
là một cái nhìn tích cực) bởi một số ký tự là bội của 7. 'g' là làm cho biểu thức chạy qua tất cả các chuỗi, không dừng lại ở lần khớp đầu tiên.
Bây giờ chuyển đổi từng phần thành số nguyên và tính toán phần còn lại bằng cách reduce
(thêm lại phần còn lại trước đó - hoặc 0 - nhân với công suất chính xác của 10):
reducer = (rem, piece) => (rem * Math.pow(10, digits) + piece) % divisor
Điều này sẽ hoạt động vì thuật toán còn lại "trừ":
n mod d = (n - kd) mod d
cho phép thay thế bất kỳ 'phần ban đầu' nào của biểu diễn thập phân của một số bằng phần còn lại của nó, mà không ảnh hưởng đến phần còn lại cuối cùng.
Mã cuối cùng sẽ trông như sau:
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
ước tính là 1,5. Đảm bảo xử lý (parseInt, sàn, v.v.) theo yêu cầu