Java thực hiện các phép tính modulus với số âm như thế nào?


93

Tôi có đang làm sai mô-đun không? Bởi vì trong Java -13 % 64được cho là để đánh giá -13nhưng tôi nhận được 51.


102
@Dan Ngay cả khi không có khoảng trống chính tĩnh ... Tôi thấy mã.
Joris Meys

22
Tôi nhận được -13 & 64 == -13
Grodriguez

7
Nó thế nào , bạn đang nhận được 51 giờ so với -13.
Raedwald

3
Bạn không thực hiện mô-đun nào cả. Không có toán tử modulo trong Java. %là một toán tử phần dư.
Marquis of Lorne,

3
Câu hỏi khó hiểu: Java 8 cho -13, như một số người khác nói. Phiên bản Java nào mà bạn cho là có được điều đó?
Jan Żankowski

Câu trả lời:


104

Cả hai định nghĩa về môđun của số âm đều được sử dụng - một số ngôn ngữ sử dụng một định nghĩa này và một số ngôn ngữ khác.

Nếu bạn muốn nhận một số âm cho đầu vào âm thì bạn có thể sử dụng điều này:

int r = x % n;
if (r > 0 && x < 0)
{
    r -= n;
}

Tương tự như vậy nếu bạn đang sử dụng một ngôn ngữ trả về một số âm trên đầu vào âm và bạn muốn khẳng định:

int r = x % n;
if (r < 0)
{
    r += n;
}

3
Điều này không hoạt động tốt nếu n là số âm. Nếu bạn sử dụng cùng một ví dụ từ Java 7 Lang Spec (Phần 15.17.3): (-5)% (-3) = -2. Thêm -3 sẽ không hoạt động. Bạn nên thêm giá trị tuyệt đối của n nếu bạn muốn chắc chắn rằng giá trị đó là dương.
partlov

6
Trong Java, modulo phủ định không thay đổi bất cứ điều gì, nếu bạn sử dụng Abs (), chỉ cần viết r = x% abs (n). Tôi không thích câu lệnh if, tôi muốn viết r = ((x% n) + n)% n. Liên quan đến sức mạnh của 2 modulo (2,4,8,16, v.v.) và câu trả lời khẳng định, hãy xem xét mặt nạ nhị phân r = x & 63.
Fabyen

3
Trong ngữ cảnh của Java (theo thẻ câu hỏi), câu trả lời này về cơ bản là "sai". Cho biểu thức x % y, A) nếu xlà âm thì phần còn lại là âm, tức là x % y == -(-x % y). B) dấu hiệu của ykhông có hiệu lực tức làx % y == x % -y
Bohemian

72

Vì "về mặt toán học" cả hai đều đúng:

-13 % 64 = -13 (on modulus 64)  
-13 % 64 = 51 (on modulus 64)

Một trong những tùy chọn phải được chọn bởi các nhà phát triển ngôn ngữ Java và họ đã chọn:

dấu của kết quả bằng dấu của cổ tức.

Nói nó trong thông số kỹ thuật Java:

https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.17.3


8
Câu hỏi đặt ra là "tại sao Java lại cho tôi -13 % 64 = 51khi tôi mong đợi -13?".
Pascal Cuoq

5
@pascal: java cung cấp cho bạn định nghĩa đúng trong toán học và cách nó được triển khai để làm điều đó không phải là điều bạn mong đợi từ nó.

9
Hành vi lành mạnh về mặt toán học có sẵn trong Java 8: Math.floorMod
Jesse Glick vào

1
Một cái gì đó trong 15.17.3 của họ . Ví dụ về % toán tử còn lại không rõ ràng. int result = (-5) % 3;cho -2. int result = (-3) % 5;cho -3. Nói chung, int result = (-a) % b;đưa ra câu trả lời đúng khi | -a | > b. Để có được kết quả thích hợp khi | -a | <b chúng ta nên bọc số chia. int result = ((-a) % b) + b;cho một tiêu cực hay int result = (((-a) % b) + b) % b;cho một tích cực hay tiêu cực
Oz Edri

@Caner Tôi không hiểu điều này, Làm thế nào cả hai có thể giống nhau?
Kishore Kumar Korada

20

Bạn có chắc mình đang làm việc trong Java? 'vì Java cho -13% 64 = -13 như mong đợi. Dấu hiệu của cổ tức!


15

Kết quả của bạn là sai đối với Java. Vui lòng cung cấp một số ngữ cảnh mà bạn đến với nó (chương trình, cách triển khai và phiên bản Java của bạn).

Từ đặc tả ngôn ngữ Java

15.17.3 Toán tử phần dư%
[...]
Phép toán phần dư cho các toán hạng là số nguyên sau khi thăng hạng số nhị phân (§5.6.2) tạo ra giá trị kết quả sao cho (a / b) * b + (a% b) bằng a.
15.17.2 Toán tử bộ phận /
[...] Phép chia
số nguyên làm tròn về phía 0.

Vì / được làm tròn về phía 0 (kết quả bằng 0), kết quả của% sẽ là số âm trong trường hợp này.


Một cái gì đó trong 15.17.3 của họ . Ví dụ về % toán tử còn lại không rõ ràng. int result = (-5) % 3;Cho -2 int result = (-3) % 5;cho -3 Nói chung, int result = (-a) % b;đưa ra câu trả lời đúng khi | -a | > b Để nhận được kết quả thích hợp khi | -a | <b chúng ta nên bọc số chia. int result = ((-a) % b) + b;đối với âm a hoặc int result = (((-a) % b) + b) % b;dương hoặc âm a.
Oz Edri

1
Nhận xét của bạn là khá rõ ràng. Phần xác định kết quả chính xác và các ví dụ đồng ý với định nghĩa đó. Đối với ví dụ của bạn (-3) % 5, kết quả chính xác theo định nghĩa là -3, và việc triển khai đúng Java sẽ tạo ra kết quả đó.
starblue

Tôi đoán tôi đã không giải thích chính xác về mình. Ý tôi nói về "câu trả lời đúng" khi | -a | <b là để có được kết quả dương tính, chúng ta nên "gói" kết quả đã cho từ a% b bằng cách thêm b vào nó. Trong ví dụ của tôi, (-3)%5thực sự mang lại cho -3, và nếu chúng ta muốn thời gian còn lại tích cực chúng ta nên thêm từ 5 đến nó, và sau đó kết quả sẽ là2
Oz Edri

6

bạn có thể dùng

(x % n) - (x < 0 ? n : 0);

3
@ruslik Bạn cũng có thể làm: ((x % k) + k) % k. (Mặc dù bạn có lẽ là dễ đọc hơn.)
John Kurlak

2
@JohnKurlak Phiên bản của bạn hoạt động như thế này: 4% 3 = 1 HOẶC 4% -3 = -2 HOẶC -4% 3 = 2 HOẶC -4% -3 = -1 nhưng phiên bản từ ruslik hoạt động như thế này: 4% 3 = 1 HOẶC 4% -3 = 1 HOẶC -4% 3 = -4 HOẶC -4% -3 = 2
Joschua

1
@Joschua Cảm ơn bạn đã chỉ ra điều này. Mã của tôi hữu ích khi bạn muốn kết quả mô đun nằm trong phạm vi [0, sign(divisor) * divisor)thay vì [0, sign(dividend) * divisor).
John Kurlak

3

Câu trả lời của bạn là trong wikipedia: hoạt động modulo

Nó nói rằng trong Java, dấu hiệu trên hoạt động modulo giống như dấu hiệu của hoạt động cổ tức. và vì chúng ta đang nói về phần còn lại của phép chia là tốt, nó trả về -13 trong trường hợp của bạn, vì -13/64 = 0. -13-0 = -13.

EDIT: Xin lỗi, đã hiểu nhầm câu hỏi của bạn ... Bạn nói đúng, java nên cho -13. Bạn có thể cung cấp thêm mã xung quanh?


2

Modulo số học với toán hạng âm được xác định bởi nhà thiết kế ngôn ngữ, người có thể để nó cho việc triển khai ngôn ngữ, người có thể trì hoãn định nghĩa cho kiến ​​trúc CPU.

Tôi không thể tìm thấy định nghĩa ngôn ngữ Java.
Cảm ơn Ishtar, Đặc tả ngôn ngữ Java cho Toán tử phần còn lại% nói rằng dấu của kết quả giống như dấu của tử số.


1

Để khắc phục điều này, bạn có thể thêm 64(hoặc bất kỳ cơ sở mô đun của bạn là gì) vào giá trị âm cho đến khi nó là dương

int k = -13;
int modbase = 64;

while (k < 0) {
    k += modbase;
}

int result = k % modbase;

Kết quả sẽ vẫn nằm trong cùng một lớp tương đương.


1

x = x + m = x - mtrong mô đun m.
như vậy -13 = -13 + 64trong modulus 64-13 = 51trong modulus 64.
giả sử Z = X * d + r, nếu 0 < r < Xsau đó trong phép chia Z/Xchúng ta gọi rlà phần dư.
Z % Xtrả về phần còn lại của Z/X.


1

Hàm mod được định nghĩa là số lượng mà một số vượt quá bội số nguyên lớn nhất của ước số không lớn hơn số đó. Vì vậy, trong trường hợp của bạn

-13 % 64

bội số nguyên lớn nhất của 64 không vượt quá -13 là -64. Bây giờ, khi bạn trừ -13 khỏi -64, nó bằng 51-13 - (-64) = -13 + 64 = 51


0

Trong phiên bản Java JDK 1.8.0_05 -13% 64 = -13 của tôi

bạn có thể thử -13- (int (-13/64)) nói cách khác là thực hiện phép chia chuyển thành một số nguyên để loại bỏ phần phân số sau đó trừ khỏi tử số Vì vậy tử số- (int (tử số / mẫu số)) sẽ cho kết quả chính xác phần còn lại và ký tên


0

Trong phiên bản mới nhất của Java mà bạn nhận được -13%64 = -13. Câu trả lời sẽ luôn có dấu của tử số.


Thay đổi này được thực hiện trong phiên bản nào?
NightShadeQueen

Trong java 7 nó đề cập rõ ràng mod đó sẽ có dấu hiệu của tử số :)
rayasam Harish VSN

@NightShadeQueen Nó không bao giờ được thay đổi.
Marquis of Lorne

0

Theo phần 15.17.3 của JLS, "Phép toán phần còn lại cho các toán hạng là số nguyên sau khi thăng hạng số nhị phân tạo ra giá trị kết quả sao cho (a / b) * b + (a% b) bằng a. Nhận dạng này là số chẵn trong trường hợp đặc biệt, số bị chia là số nguyên âm có độ lớn lớn nhất có thể cho loại của nó và số chia là -1 (phần còn lại là 0). "

Hy vọng rằng sẽ giúp.


-1

Tôi không nghĩ rằng Java trả về 51 trong trường hợp này. Tôi đang chạy Java 8 trên máy Mac và tôi nhận được:

-13 % 64 = -13

Chương trình:

public class Test {
    public static void main(String[] args) {
        int i = -13;
        int j = 64;
        System.out.println(i % j);
    }
}

5
@XaverKapeller, không! Nhiều người chỉ ra rằng về mặt toán học -13 và 51 là đúng. Trong Java, -13 là câu trả lời được mong đợi và đó là câu trả lời tôi cũng nhận được, vì vậy tôi không biết làm thế nào mà người gửi nhận được 51, đó là một bí ẩn. Chi tiết chế độ về ngữ cảnh có thể giúp trả lời chính xác câu hỏi này.
Fabyen

@Xaver Kapeller: Làm thế nào để cả 51 và -13 đều đúng? Java sẽ trở lại chỉ là một giá trị ..
ceprateek

@XaverKapeller Làm thế nào để một câu trả lời ghi lại những gì Java thực sự có thể sai?
Marquis of Lorne

@EJP Tôi nghĩ 3 năm trước khi tôi viết bài này, tôi đã đủ ngớ ngẩn để coi trọng độ chính xác toán học hơn thực tế đơn giản về cách java giải quyết vấn đề này. Cảm ơn vì đã nhắc tôi xóa bình luận ngu ngốc của mình: D
Xaver Kapeller
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.