Trong java khi bạn làm
a % b
Nếu a là âm, nó sẽ trả về kết quả âm, thay vì quấn quanh b như bình thường. Cách tốt nhất để sửa lỗi này là gì? Cách duy nhất tôi có thể nghĩ là
a < 0 ? b + a : a % b
Trong java khi bạn làm
a % b
Nếu a là âm, nó sẽ trả về kết quả âm, thay vì quấn quanh b như bình thường. Cách tốt nhất để sửa lỗi này là gì? Cách duy nhất tôi có thể nghĩ là
a < 0 ? b + a : a % b
Câu trả lời:
Nó hoạt động như nó phải a% b = a - a / b * b; tức là nó là phần còn lại.
Bạn có thể làm (a% b + b)% b
Biểu thức này hoạt động vì kết quả của (a % b)
nhất thiết phải thấp hơn b
, bất kể a
là dương hay âm. Việc thêm b
sẽ quan tâm đến các giá trị âm a
, vì (a % b)
là giá trị âm giữa -b
và 0
, (a % b + b)
nhất thiết phải thấp hơn b
và dương. Mô-đun cuối cùng ở đó trong trường hợp a
bắt đầu là tích cực, vì nếu a
là tích cực (a % b + b)
sẽ trở nên lớn hơn b
. Do đó, hãy (a % b + b) % b
biến nó thành nhỏ hơn b
một lần nữa (và không ảnh hưởng đến các a
giá trị âm ).
(a % b)
nhất thiết phải thấp hơn b
(bất kể a
là tích cực hay tiêu cực), việc thêm b
sẽ quan tâm đến các giá trị âm của a
, vì (a % b)
thấp hơn b
và thấp hơn 0
, (a % b + b)
nhất thiết phải thấp hơn b
và dương. Mô-đun cuối cùng ở đó trong trường hợp a
bắt đầu là tích cực, vì nếu a
là tích cực (a % b + b)
sẽ trở nên lớn hơn b
. Do đó, hãy (a % b + b) % b
biến nó thành nhỏ hơn b
một lần nữa (và không ảnh hưởng đến các a
giá trị âm ).
a < 0
, có lẽ bạn có thể có một cái nhìn)
(a % b + b) % b
chia nhỏ cho các giá trị rất lớn của a
và b
. Ví dụ, sử dụng a = Integer.MAX_VALUE - 1
và b = Integer.MAX_VALUE
sẽ cho -3
kết quả là một số âm, đó là điều bạn muốn tránh.
while
sẽ chậm hơn nếu bạn thực sự cần ngoại trừ bạn chỉ cần một if
trong trường hợp đó, nó thực sự nhanh hơn.
Kể từ Java 8, bạn có thể sử dụng Math.floorMod (int x, int y) và Math.floorMod (long x, long y) . Cả hai phương pháp này đều trả về kết quả giống như câu trả lời của Peter.
Math.floorMod( 2, 3) = 2
Math.floorMod(-2, 3) = 1
Math.floorMod( 2, -3) = -1
Math.floorMod(-2, -3) = -2
float
hoặc double
đối số. Toán tử nhị phân mod ( %
) cũng hoạt động với float
và double
toán hạng.
Đối với những người chưa sử dụng (hoặc không thể sử dụng) Java 8, Guava đã giải cứu với IntMath.mod () , có sẵn kể từ Guava 11.0.
IntMath.mod( 2, 3) = 2
IntMath.mod(-2, 3) = 1
Một lưu ý: không giống như Math.floorMod () của Java 8, số chia (tham số thứ hai) không được âm.
Trong lý thuyết số, kết quả luôn là số dương. Tôi đoán rằng điều này không phải lúc nào cũng đúng trong ngôn ngữ máy tính vì không phải tất cả các lập trình viên đều là nhà toán học. Hai xu của tôi, tôi sẽ coi đó là một khiếm khuyết thiết kế của ngôn ngữ, nhưng bạn không thể thay đổi nó bây giờ.
= MOD (-4,180) = 176 = MOD (176, 180) = 176
vì 180 * (-1) + 176 = -4 giống 180 * 0 + 176 = 176
Sử dụng ví dụ về đồng hồ ở đây, http://mathworld.wolfram.com/Congruence.html , bạn sẽ không nói thời lượng_of_time mod cycle_length là -45 phút, bạn sẽ nói là 15 phút, mặc dù cả hai câu trả lời đều thỏa mãn phương trình cơ sở.
-1
thay vì n-1
) sau đó có tại nó.
Java 8 có Math.floorMod
, nhưng nó rất chậm (triển khai của nó có nhiều phép chia, phép nhân và một điều kiện). Tuy nhiên, có thể JVM có một sơ khai được tối ưu hóa nội tại cho nó, điều này sẽ tăng tốc đáng kể.
Cách nhanh nhất để làm điều này mà không floorMod
có giống như một số câu trả lời khác ở đây, nhưng không có nhánh có điều kiện và chỉ có một %
op chậm .
Giả sử n là số dương và x có thể là bất kỳ thứ gì:
int remainder = (x % n); // may be negative if x is negative
//if remainder is negative, adds n, otherwise adds 0
return ((remainder >> 31) & n) + remainder;
Kết quả khi n = 3
:
x | result
----------
-4| 2
-3| 0
-2| 1
-1| 2
0| 0
1| 1
2| 2
3| 0
4| 1
Nếu bạn chỉ cần sự phân bố đồng đều giữa 0
và n-1
và không phải toán tử mod chính xác, và của bạn x
không cụm lại gần 0
, thì phần sau sẽ thậm chí còn nhanh hơn, vì có nhiều mức lệnh song song hơn và %
tính toán chậm sẽ xảy ra song song với phần khác vì chúng không phụ thuộc vào kết quả của nó.
return ((x >> 31) & (n - 1)) + (x % n)
Kết quả cho phần trên với n = 3
:
x | result
----------
-5| 0
-4| 1
-3| 2
-2| 0
-1| 1
0| 0
1| 1
2| 2
3| 0
4| 1
5| 2
Nếu đầu vào là ngẫu nhiên trong phạm vi đầy đủ của một int, phân phối của cả hai nghiệm sẽ giống nhau. Nếu các cụm đầu vào gần bằng 0, sẽ có quá ít kết quả ở n - 1
giải pháp thứ hai.
Đây là một giải pháp thay thế:
a < 0 ? b-1 - (-a-1) % b : a % b
Công thức này có thể nhanh hơn hoặc không nhanh hơn công thức khác [(a% b + b)% b]. Không giống như công thức khác, nó chứa một nhánh, nhưng sử dụng một thao tác ít mô đun hơn. Có thể là một chiến thắng nếu máy tính có thể dự đoán đúng <0.
(Chỉnh sửa: Đã sửa công thức.)