Bagaimana java melakukan kalkulasi modulus dengan bilangan negatif?

96

Apakah saya salah melakukan modulus? Karena di jawa -13 % 64seharusnya di evaluasi -13tapi saya dapatkan 51.

Jakir00
sumber
102
@Dan Bahkan tanpa kekosongan utama statis ... Saya melihat kode.
Joris Meys
22
Saya mendapatkan -13 & 64 == -13
Grodriguez
7
Bagaimana Anda mendapatkan 51 ratehr dari -13.
Raedwald
3
Anda tidak melakukan modulus sama sekali. Tidak ada operator modulo di Jawa. %adalah operator sisa.
Marquis dari Lorne
3
Pertanyaan membingungkan: Java 8 memberikan -13, seperti yang dikatakan beberapa orang lain. Versi Java mana yang seharusnya Anda dapatkan?
Jan Żankowski

Jawaban:

105

Kedua definisi modulus bilangan negatif digunakan - beberapa bahasa menggunakan satu definisi dan beberapa bahasa lainnya.

Jika Anda ingin mendapatkan angka negatif untuk input negatif, Anda dapat menggunakan ini:

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

Demikian juga jika Anda menggunakan bahasa yang mengembalikan angka negatif pada masukan negatif dan Anda lebih suka positif:

int r = x % n;
if (r < 0)
{
    r += n;
}
Mark Byers
sumber
3
Ini tidak berfungsi dengan baik jika n negatif. Jika Anda menggunakan contoh yang sama dari Java 7 Lang Spec (Bagian 15.17.3): (-5)% (-3) = -2. Menambahkan -3 tidak akan berhasil. Anda harus menambahkan nilai absolut n jika Anda ingin memastikan bahwa nilainya positif.
partlov
6
Di Java modulo negatif tidak mengubah apa pun, jika Anda menggunakan Abs (), tulis saja r = x% abs (n). Saya tidak suka jika pernyataan, saya lebih suka menulis r = ((x% n) + n)% n. Mengenai pangkat 2 modulo (2,4,8,16, dst.) Dan jawaban positif, pertimbangkan topeng biner r = x & 63.
Fabyen
3
Dalam konteks Java (sesuai tag pertanyaan) jawaban ini pada dasarnya "salah". Diketahui ungkapan x % y, A) jika xnegatif sisanya negatif, yaitu x % y == -(-x % y). B) tanda ytidak berpengaruh yaitux % y == x % -y
Bohemian
72

Karena "secara matematis" keduanya benar:

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

Salah satu opsi harus dipilih oleh pengembang bahasa Java dan mereka memilih:

tanda hasilnya sama dengan tanda dividen.

Mengatakannya dalam spesifikasi Java:

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

Caner
sumber
8
Pertanyaannya adalah "mengapa Java memberi saya -13 % 64 = 51ketika saya mengharapkan -13?".
Pascal Cuoq
5
@pascal: java memberi Anda definisi yang tepat dalam matematika dan cara penerapannya untuk melakukan itu, bukan yang Anda harapkan darinya.
9
Perilaku matematis waras tersedia di Java 8: Math.floorMod
Jesse Glick
1
Sesuatu di 15.17.3 mereka . Contoh % Operator Sisa tidak jelas. int result = (-5) % 3;memberikan -2. int result = (-3) % 5;memberikan -3. Secara umum, int result = (-a) % b;memberikan jawaban yang benar saat | -a | > b. Untuk mendapatkan hasil yang tepat saat | -a | <b kita harus membungkus pembagi. int result = ((-a) % b) + b;untuk negatif a atau int result = (((-a) % b) + b) % b;untuk positif atau negatif a
Oz Edri
@ Caner Saya tidak mengerti ini, Bagaimana keduanya bisa sama?
Kishore Kumar Korada
20

Apakah Anda yakin Anda bekerja di Java? Karena Java memberikan -13% 64 = -13 seperti yang diharapkan. Tanda dividen!

Keyxeq
sumber
15

Hasil Anda salah untuk Java. Berikan beberapa konteks bagaimana Anda sampai padanya (program Anda, implementasi dan versi Java).

Dari Spesifikasi Bahasa Java

15.17.3 Operator Sisa%
[...]
Operasi sisa untuk operan yang merupakan bilangan bulat setelah promosi numerik biner (§5.6.2) menghasilkan nilai hasil sehingga (a / b) * b + (a% b) sama dengan Sebuah.
15.17.2 Operator Divisi /
[...]
Divisi integer membulatkan ke arah 0.

Karena / dibulatkan menuju nol (menghasilkan nol), hasil% harus negatif dalam kasus ini.

starblue
sumber
Sesuatu di 15.17.3 mereka . Contoh % Operator Sisa tidak jelas. int result = (-5) % 3;memberi -2 int result = (-3) % 5;memberi -3 Secara umum, int result = (-a) % b;memberikan jawaban yang benar jika | -a | > b Untuk mendapatkan hasil yang tepat saat | -a | <b kita harus membungkus pembagi. int result = ((-a) % b) + b;untuk negatif a atau int result = (((-a) % b) + b) % b;untuk positif atau negatif a.
Oz Edri
1
Komentar Anda kurang jelas. Bagian ini menjelaskan hasil yang benar, dan contoh sesuai dengan definisi tersebut. Untuk contoh Anda (-3) % 5, hasil yang benar menurut definisi adalah -3, dan implementasi Java yang benar akan menghasilkan hasil itu.
starblue
Saya kira saya tidak menjelaskan diri saya dengan benar. Yang saya maksud dengan "jawaban yang benar" ketika | -a | <b adalah bahwa untuk mendapatkan hasil positif kita harus "membungkus" hasil yang diberikan dari a% b dengan menambahkan b padanya. Dalam contoh saya, (-3)%5memang memberi -3, dan jika kita menginginkan sisa positif kita harus menambahkan 5 padanya, dan kemudian hasilnya adalah2
Oz Edri
6

kamu bisa memakai

(x % n) - (x < 0 ? n : 0);
ruslik
sumber
3
@ruslik Anda juga dapat melakukan: ((x % k) + k) % k. (Meskipun milik Anda mungkin lebih mudah dibaca.)
John Kurlak
2
@JohnKurlak You versi Anda bekerja seperti ini: 4% 3 = 1 ATAU 4% -3 = -2 ATAU -4% 3 = 2 ATAU -4% -3 = -1 tetapi yang dari ruslik berfungsi seperti ini: 4% 3 = 1 ATAU 4% -3 = 1 ATAU -4% 3 = -4 ATAU -4% -3 = 2
Joschua
1
@Joschua Terima kasih telah menunjukkan hal ini. Kode saya berguna ketika Anda ingin hasil modulus berada dalam kisaran, [0, sign(divisor) * divisor)bukan [0, sign(dividend) * divisor).
John Kurlak
3

Jawaban Anda ada di wikipedia: operasi modulo

Dikatakan, bahwa di Jawa tanda operasi modulo sama dengan dividen. dan karena kita berbicara tentang operasi pembagian lainnya baik-baik saja, ia mengembalikan -13 dalam kasus Anda, karena -13/64 = 0. -13-0 = -13.

EDIT: Maaf, salah paham pertanyaan Anda ... Anda benar, java harus memberikan -13. Bisakah Anda memberikan lebih banyak kode sekitarnya?

Nava Carmon
sumber
2

Aritmatika modulo dengan operan negatif ditentukan oleh perancang bahasa, yang mungkin menyerahkannya pada implementasi bahasa, yang mungkin akan menunda definisi ke arsitektur CPU.

Saya tidak dapat menemukan definisi bahasa Java.
Terima kasih Ishtar, Spesifikasi Bahasa Java untuk Operator Sisa% mengatakan bahwa tanda hasil sama dengan tanda pembilang.

wallyk
sumber
1

Untuk mengatasinya, Anda dapat menambahkan 64(atau apa pun basis modulus Anda) ke nilai negatif hingga bernilai positif

int k = -13;
int modbase = 64;

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

int result = k % modbase;

Hasilnya akan tetap berada di kelas kesetaraan yang sama.

Andreas
sumber
1

x = x + m = x - mdalam modulus m.
jadi -13 = -13 + 64di modulus 64 dan -13 = 51di modulus 64.
asumsikan Z = X * d + r, jika 0 < r < Xkemudian di divisi Z/Xkita sebut rsisanya.
Z % Xmengembalikan sisa Z/X.


sumber
1

Fungsi mod didefinisikan sebagai jumlah yang melebihi kelipatan bilangan bulat terbesar dari pembagi yang tidak lebih besar dari bilangan tersebut. Jadi dalam kasus Anda

-13 % 64

kelipatan bilangan bulat terbesar dari 64 yang tidak melebihi -13 adalah -64. Sekarang, jika Anda mengurangi -13 dari -64, hasilnya menjadi 51-13 - (-64) = -13 + 64 = 51

Salman Paracha
sumber
0

Dalam versi saya Java JDK 1.8.0_05 -13% 64 = -13

Anda bisa mencoba -13- (int (-13/64)) dengan kata lain melakukan pembagian dilemparkan ke bilangan bulat untuk menghilangkan bagian pecahan kemudian mengurangi pembilang Jadi pembilang- (int (pembilang / penyebut)) harus memberikan yang benar sisa & tanda tangan

Robert Green
sumber
0

Di Java versi terbaru yang Anda dapatkan -13%64 = -13. Jawabannya akan selalu bertanda pembilang.

vsn harish rayasam
sumber
Dalam versi manakah perubahan ini dilakukan?
NightShadeQueen
Di java 7 jelas disebutkan bahwa mod akan memiliki tanda pembilang :)
vsn harish rayasam
@NightShadeQueen Itu tidak pernah berubah.
Marquis dari Lorne
0

Menurut bagian 15.17.3 dari JLS, "Operasi sisa untuk operand yang merupakan bilangan bulat setelah promosi numerik biner menghasilkan nilai hasil sehingga (a / b) * b + (a% b) sama dengan a. Identitas ini berlaku genap dalam kasus khusus bahwa pembagi adalah bilangan bulat negatif dari kemungkinan besar terbesar untuk tipenya dan pembaginya -1 (sisanya adalah 0). "

Semoga membantu.

kudesiaji
sumber
-1

Saya tidak berpikir Java mengembalikan 51 dalam kasus ini. Saya menjalankan Java 8 di Mac dan saya mendapatkan:

-13 % 64 = -13

Program:

public class Test {
    public static void main(String[] args) {
        int i = -13;
        int j = 64;
        System.out.println(i % j);
    }
}
ceprateek
sumber
5
@XaverKapeller, tidak! Banyak orang menunjukkan bahwa secara matematis -13 dan 51 benar. Di Java, -13 adalah jawaban yang diharapkan, dan itu yang saya dapatkan juga, jadi saya tidak tahu bagaimana pengirim mendapat 51, itu misteri. Detail mode tentang konteks dapat membantu menjawab pertanyaan ini dengan benar.
Fabyen
@Xaver Kapeller: Bagaimana 51 dan -13 bisa benar? Java akan mengembalikan hanya satu nilai ..
ceprateek
@XaverKapeller Bagaimana sebuah jawaban yang mendokumentasikan apa yang sebenarnya dilakukan Java mungkin salah?
Marquis dari Lorne
@EJP Saya pikir 3 tahun yang lalu ketika saya menulis ini saya cukup bodoh untuk menilai akurasi matematika lebih dari kenyataan sederhana tentang bagaimana java menangani ini. Terima kasih telah mengingatkan saya untuk menghapus komentar bodoh saya: D
Xaver Kapeller