java ทำการคำนวณโมดูลัสด้วยจำนวนลบอย่างไร


96

ฉันทำโมดูลัสผิดหรือเปล่า? เพราะใน Java -13 % 64ควรจะประเมินแต่ฉันได้รับ-1351


102
@ แดนแม้จะไม่มีโมฆะหลักคง ... ฉันเห็นรหัส
Joris Meys

22
ฉันได้รับ -13 & 64 == -13
Grodriguez

7
เป็นอย่างไรบ้างที่คุณได้รับ 51 อัตรามากกว่า -13
Raedwald

3
คุณไม่ได้ทำโมดูลัสเลย ไม่มีตัวดำเนินการโมดูโลใน Java %เป็นตัวดำเนินการส่วนที่เหลือ
Marquis of Lorne

3
คำถามที่สับสน: Java 8 ให้ -13 อย่างที่คนอื่นพูด คุณควรได้รับ Java เวอร์ชันใด
ม.ค. Żankowski

คำตอบ:


105

มีการใช้คำจำกัดความทั้งสองของโมดูลัสของจำนวนลบ - บางภาษาใช้คำจำกัดความเดียวและอีกคำหนึ่ง

หากคุณต้องการรับจำนวนลบสำหรับอินพุตเชิงลบคุณสามารถใช้สิ่งนี้:

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

ในทำนองเดียวกันหากคุณกำลังใช้ภาษาที่ส่งคืนจำนวนลบในอินพุตเชิงลบและคุณต้องการค่าบวก:

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

3
สิ่งนี้ไม่ได้ผลถ้า n เป็นลบ หากคุณใช้ตัวอย่างเดียวกันจาก Java 7 Lang Spec (มาตรา 15.17.3): (-5)% (-3) = -2 การเพิ่ม -3 จะไม่ทำงาน คุณควรเพิ่มค่าสัมบูรณ์ของ n ถ้าคุณต้องการให้แน่ใจว่าค่านั้นเป็นบวก
partlov

6
ในโมดูโลเชิงลบของ Java จะไม่เปลี่ยนแปลงอะไรเลยหากคุณใช้ Abs () ต่อไปให้เขียน r = x% abs (n) ฉันไม่ชอบคำสั่ง if ฉันอยากจะเขียน r = ((x% n) + n)% n เกี่ยวกับพลังของ 2 โมดูโล (2,4,8,16 ฯลฯ .. ) และคำตอบเชิงบวกให้พิจารณารูปแบบไบนารี r = x & 63
Fabyen

3
ในบริบทของ Java (ตามแท็กคำถาม) คำตอบนี้ "ผิด" เป็นหลัก ได้รับการแสดงออกx % y, A) ถ้าเป็นลบที่เหลือเป็นลบคือx x % y == -(-x % y)B) สัญญาณyไม่มีผลคือx % y == x % -y
โบฮีเมียน

72

เนื่องจาก "ทางคณิตศาสตร์" ทั้งสองถูกต้อง:

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

หนึ่งในตัวเลือกนั้นจะต้องถูกเลือกโดยนักพัฒนาภาษา Java และพวกเขาเลือก:

เครื่องหมายของผลลัพธ์เท่ากับเครื่องหมายของเงินปันผล

กล่าวไว้ในข้อกำหนด Java:

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


8
คำถามคือ "ทำไม Java ถึงให้ฉัน-13 % 64 = 51เมื่อฉันคาดหวัง-13?"
Pascal Cuoq

5
@pascal: java ให้คำจำกัดความที่ถูกต้องในทางคณิตศาสตร์และวิธีที่นำไปใช้เพื่อทำสิ่งนั้นไม่ใช่สิ่งที่คุณคาดหวังจากมัน

9
พฤติกรรมที่มีเหตุผลทางคณิตศาสตร์มีอยู่ใน Java 8: Math.floorMod
Jesse Glick

1
บางอย่างใน15.17.3 ตัวอย่าง% ตัวดำเนินการที่เหลือไม่ชัดเจน int result = (-5) % 3;ให้ -2 int result = (-3) % 5;ให้ -3. โดยทั่วไปint result = (-a) % b;จะให้คำตอบที่ถูกต้องเมื่อ | -a | > ข. เพื่อให้ได้ผลลัพธ์ที่เหมาะสมเมื่อ | -a | <b เราควรรวมตัวหาร int result = ((-a) % b) + b;สำหรับลบ a หรือint result = (((-a) % b) + b) % b;บวกหรือลบ a
Oz Edri

@ Caner ฉันไม่เข้าใจสิ่งนี้ทั้งคู่จะเหมือนกันได้อย่างไร?
Kishore Kumar Korada

20

แน่ใจหรือว่ากำลังทำงานใน Java? 'ทำให้ Java ให้ -13% 64 = -13 ตามที่คาดไว้ ราศีปันผล!


15

ผลลัพธ์ของคุณไม่ถูกต้องสำหรับ Java โปรดระบุบริบทว่าคุณมาถึงมันได้อย่างไร (โปรแกรมการใช้งานและเวอร์ชันของ Java)

จากข้อกำหนดภาษา Java

15.17.3 ตัวดำเนินการที่เหลือ%
[... ]
การดำเนินการส่วนที่เหลือสำหรับตัวถูกดำเนินการที่เป็นจำนวนเต็มหลังจากการเลื่อนตำแหน่งตัวเลขไบนารี (§5.6.2) จะสร้างค่าผลลัพธ์ที่ (a / b) * b + (a% b) เท่ากับ ก.
15.17.2 ตัวดำเนินการหาร /
[... ] การ
หารจำนวนเต็มปัดเศษเข้าหา 0

เนื่องจาก / ถูกปัดเศษเป็นศูนย์ (ผลลัพธ์เป็นศูนย์) ผลลัพธ์ของ% ควรเป็นลบในกรณีนี้


บางอย่างใน15.17.3 ตัวอย่าง% ตัวดำเนินการที่เหลือไม่ชัดเจน int result = (-5) % 3;ให้ -2 int result = (-3) % 5;ให้ -3 โดยทั่วไปint result = (-a) % b;ให้คำตอบที่ถูกต้องเมื่อ | -a | > b เพื่อให้ได้ผลลัพธ์ที่เหมาะสมเมื่อ | -a | <b เราควรรวมตัวหาร int result = ((-a) % b) + b;สำหรับลบ a หรือint result = (((-a) % b) + b) % b;สำหรับบวกหรือลบก.
Oz Edri

1
ความคิดเห็นของคุณค่อนข้างไม่ชัดเจน ส่วนกำหนดผลลัพธ์ที่ถูกต้องและตัวอย่างเห็นด้วยกับคำจำกัดความนั้น สำหรับตัวอย่างของคุณ(-3) % 5ผลลัพธ์ที่ถูกต้องตามคำจำกัดความคือ-3และการนำ Java ไปใช้อย่างถูกต้องควรให้ผลลัพธ์นั้น
starblue

ฉันเดาว่าฉันอธิบายตัวเองไม่ถูก "คำตอบที่ถูกต้อง" หมายถึงอะไรเมื่อ | -a | <b คือเพื่อให้ได้ผลลัพธ์ที่เป็นบวกเราควร "รวม" ผลลัพธ์ที่กำหนดจาก a% b โดยการเพิ่ม b เข้าไป ในตัวอย่างของฉัน(-3)%5ให้จริง-3และถ้าเราต้องการส่วนที่เหลือที่เป็นบวกเราควรเพิ่ม 5 เข้าไปแล้วผลลัพธ์จะเป็น2
Oz Edri

6

คุณสามารถใช้ได้

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

3
@ruslik คุณยังสามารถทำได้: ((x % k) + k) % k. (แม้ว่าของคุณอาจอ่านได้มากกว่า)
John Kurlak

2
@JohnKurlak เวอร์ชันของคุณใช้งานได้เช่นนี้: 4% 3 = 1 หรือ 4% -3 = -2 หรือ -4% 3 = 2 หรือ -4% -3 = -1 แต่อันที่มาจาก ruslik ทำงานดังนี้: 4% 3 = 1 หรือ 4% -3 = 1 หรือ -4% 3 = -4 หรือ -4% -3 = 2
Joschua

1
@Joschua ขอบคุณที่ชี้ให้เห็นสิ่งนี้ รหัสของฉันจะเป็นประโยชน์สำหรับเมื่อคุณต้องการผลโมดูลัสจะอยู่ในช่วงของการแทน[0, sign(divisor) * divisor) [0, sign(dividend) * divisor)
John Kurlak

3

คำตอบของคุณอยู่ในวิกิพีเดีย: การทำงานของโมดูโล

มันบอกว่าใน Java เครื่องหมายบนการทำงานของโมดูโลจะเหมือนกับการจ่ายเงินปันผล และเนื่องจากเรากำลังพูดถึงส่วนที่เหลือของการดำเนินการหารก็ใช้ได้ผลตอบแทน -13 ในกรณีของคุณตั้งแต่ -13/64 = 0. -13-0 = -13

แก้ไข: ขออภัยเข้าใจคำถามของคุณผิด ... คุณพูดถูก java ควรให้ -13 คุณสามารถระบุรหัสโดยรอบเพิ่มเติมได้หรือไม่?


2

การคำนวณทางคณิตศาสตร์ของโมดูโลที่มีตัวถูกดำเนินการเชิงลบถูกกำหนดโดยผู้ออกแบบภาษาซึ่งอาจปล่อยให้เป็นการนำภาษาไปใช้ซึ่งอาจเลื่อนการกำหนดนิยามไปยังสถาปัตยกรรมของ CPU

ฉันไม่พบนิยามภาษา Java
ขอบคุณ Ishtar ข้อกำหนดภาษา Java สำหรับตัวดำเนินการ Remainder%กล่าวว่าเครื่องหมายของผลลัพธ์เหมือนกับเครื่องหมายของตัวเศษ


1

เพื่อเอาชนะสิ่งนี้คุณสามารถเพิ่ม64(หรือฐานโมดูลัสของคุณ) เป็นค่าลบจนกว่ามันจะเป็นบวก

int k = -13;
int modbase = 64;

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

int result = k % modbase;

ผลลัพธ์จะยังคงอยู่ในระดับความเทียบเท่าเดิม


1

x = x + m = x - m ในโมดูลัส mในโมดูลัส
ดังนั้น-13 = -13 + 64ในโมดูลัส64 และในโมดูลัส-13 = 51 สมมติว่าถ้าในการหารเราเรียกส่วนที่เหลือ ผลตอบแทนส่วนที่เหลือของ64
Z = X * d + r0 < r < XZ/Xr
Z % XZ/X


1

ฟังก์ชัน mod ถูกกำหนดให้เป็นจำนวนที่ตัวเลขเกินจำนวนเต็มจำนวนเต็มมากที่สุดของตัวหารที่ไม่มากกว่าจำนวนนั้น ดังนั้นในกรณีของคุณ

-13 % 64

จำนวนเต็มผลคูณที่ใหญ่ที่สุดของ 64 ที่ไม่เกิน -13 คือ -64 ทีนี้เมื่อคุณลบ -13 จาก -64 มันจะเท่ากับ 51-13 - (-64) = -13 + 64 = 51


0

ในเวอร์ชัน Java JDK 1.8.0_05 -13% 64 = -13

คุณสามารถลอง -13- (int (-13/64)) กล่าวอีกนัยหนึ่งทำการหารเป็นจำนวนเต็มเพื่อกำจัดส่วนเศษส่วนจากนั้นลบออกจากตัวเศษดังนั้นตัวเศษ - (int (ตัวเศษ / ตัวส่วน)) ควรให้ถูกต้อง ส่วนที่เหลือและลงชื่อ


0

ใน Java -13%64 = -13รุ่นล่าสุดที่คุณได้รับ คำตอบจะมีเครื่องหมายของตัวเศษเสมอ


การเปลี่ยนแปลงนี้เกิดขึ้นในเวอร์ชันใด
NightShadeQueen

ใน java 7 มีการระบุอย่างชัดเจนว่า mod จะมีสัญลักษณ์ของตัวเศษ :)
vsn harish rayasam

@NightShadeQueen มันไม่เคยเปลี่ยน
Marquis of Lorne

0

ตามส่วนที่ 15.17.3 ของ JLS "การดำเนินการส่วนที่เหลือสำหรับตัวถูกดำเนินการที่เป็นจำนวนเต็มหลังจากการส่งเสริมตัวเลขไบนารีจะสร้างค่าผลลัพธ์ที่ (a / b) * b + (a% b) เท่ากับ a เอกลักษณ์นี้ถือได้แม้กระทั่ง ในกรณีพิเศษที่เงินปันผลคือจำนวนเต็มลบของขนาดที่ใหญ่ที่สุดที่เป็นไปได้สำหรับประเภทของมันและตัวหารคือ -1 (ส่วนที่เหลือคือ 0) "

หวังว่าจะช่วยได้


-1

ฉันไม่คิดว่า Java ส่งคืน 51 ในกรณีนี้ ฉันใช้ Java 8 บน Mac และฉันได้รับ:

-13 % 64 = -13

โปรแกรม:

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

5
@XaverKapeller ไม่! หลายคนชี้ให้เห็นว่าการพูดทางคณิตศาสตร์ -13 และ 51 นั้นถูกต้อง ใน Java -13 เป็นคำตอบที่คาดหวังและเป็นสิ่งที่ฉันได้รับเช่นกันดังนั้นฉันไม่รู้ว่าผู้ส่งมี 51 อย่างไรมันก็ลึกลับ รายละเอียดโหมดเกี่ยวกับบริบทสามารถช่วยตอบคำถามนี้ได้อย่างถูกต้อง
Fabyen

@ Xaver Kapeller: 51 และ -13 ทั้งสองอย่างถูกต้องได้อย่างไร? Java จะส่งคืนเพียงค่าเดียว ..
ceprateek

@XaverKapeller จะตอบได้อย่างไรว่าเอกสารที่ Java ทำจริงอาจจะผิด?
Marquis of Lorne

@EJP ฉันคิดว่า 3 ปีที่แล้วตอนที่ฉันเขียนสิ่งนี้ฉันโง่พอที่จะให้ความสำคัญกับความแม่นยำทางคณิตศาสตร์มากกว่าความเป็นจริงง่ายๆว่า java เกี่ยวข้องกับสิ่งนี้อย่างไร ขอบคุณที่เตือนให้ฉันลบความคิดเห็นโง่ ๆ ของฉัน: D
Xaver Kapeller
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.