ใน java เมื่อคุณทำ
a % b
ถ้า a เป็นลบมันจะส่งกลับผลลัพธ์ที่เป็นลบแทนที่จะพันรอบ b อย่างที่ควรจะเป็น วิธีใดที่ดีที่สุดในการแก้ไขปัญหานี้ วิธีเดียวที่ฉันคิดได้คือ
a < 0 ? b + a : a % b
ใน java เมื่อคุณทำ
a % b
ถ้า a เป็นลบมันจะส่งกลับผลลัพธ์ที่เป็นลบแทนที่จะพันรอบ b อย่างที่ควรจะเป็น วิธีใดที่ดีที่สุดในการแก้ไขปัญหานี้ วิธีเดียวที่ฉันคิดได้คือ
a < 0 ? b + a : a % b
คำตอบ:
มันทำงานตามที่ควร a% b = a - a / b * b; นั่นคือส่วนที่เหลือ
คุณสามารถทำได้ (a% b + b)% b
นิพจน์นี้เป็นผลลัพธ์ที่(a % b)
จำเป็นต้องต่ำกว่าb
ไม่ว่าa
จะเป็นบวกหรือลบก็ตาม เพิ่มb
ดูแลค่าลบของa
เนื่องจาก(a % b)
เป็นค่าลบระหว่าง-b
และ0
, (a % b + b)
คือจำเป็นต้องต่ำกว่าb
และบวก แบบโมดูโลสุดท้ายจะมีในกรณีที่a
เป็นบวกจะเริ่มต้นด้วยเพราะถ้าa
เป็นบวกจะกลายเป็นขนาดใหญ่กว่า(a % b + b)
b
ดังนั้น(a % b + b) % b
เปลี่ยนให้เล็กกว่าb
อีกครั้ง (และไม่มีผลต่อa
ค่าลบ)
(a % b)
จำเป็นต้องต่ำกว่าb
(ไม่ว่าถ้าa
เป็นบวกหรือลบ) เพิ่มb
ดูแลค่าลบของa
ตั้งแต่(a % b)
ต่ำกว่าb
และต่ำกว่า0
, (a % b + b)
คือจำเป็นต้องต่ำกว่าb
และบวก แบบโมดูโลสุดท้ายจะมีในกรณีที่a
เป็นบวกจะเริ่มต้นด้วยเพราะถ้าa
เป็นบวกจะกลายเป็นขนาดใหญ่กว่า(a % b + b)
b
ดังนั้น(a % b + b) % b
เปลี่ยนให้เล็กกว่าb
อีกครั้ง (และไม่มีผลต่อa
ค่าลบ)
a < 0
บางทีคุณอาจได้ดู)
(a % b + b) % b
แบ่งลงสำหรับค่ามากและa
b
ตัวอย่างเช่นการใช้a = Integer.MAX_VALUE - 1
และb = Integer.MAX_VALUE
จะให้-3
ผลลัพธ์ซึ่งเป็นจำนวนลบซึ่งเป็นสิ่งที่คุณต้องการหลีกเลี่ยง
while
จะช้ากว่าถ้าคุณต้องการจริงๆยกเว้นคุณต้องการแค่if
ในกรณีที่มันเร็วขึ้นจริง
ในฐานะของ Java 8 คุณสามารถใช้Math.floorMod (int x, y int)และMath.floorMod (ยาว x, y ยาว) ทั้งสองวิธีนี้ให้ผลลัพธ์เหมือนกันกับคำตอบของเปโตร
Math.floorMod( 2, 3) = 2
Math.floorMod(-2, 3) = 1
Math.floorMod( 2, -3) = -1
Math.floorMod(-2, -3) = -2
float
หรือdouble
ข้อโต้แย้ง Mod binary operator ( %
) ยังทำงานร่วมกับfloat
และdouble
ตัวถูกดำเนินการ
สำหรับผู้ที่ไม่ได้ใช้ (หรือไม่สามารถใช้งานได้) Java 8 แต่ Guava มาช่วยด้วยIntMath.mod ()ซึ่งมีให้ตั้งแต่ Guava 11.0
IntMath.mod( 2, 3) = 2
IntMath.mod(-2, 3) = 1
ข้อแม้อย่างหนึ่ง: ไม่เหมือนกับ Math.floorMod () ของ Java 8 ตัวหาร (พารามิเตอร์ที่สอง) ไม่สามารถเป็นค่าลบได้
ในทฤษฎีจำนวนผลลัพธ์จะเป็นบวกเสมอ ฉันเดาว่านี่ไม่ได้เป็นเช่นนั้นเสมอไปในภาษาคอมพิวเตอร์เพราะไม่ใช่ว่าโปรแกรมเมอร์ทุกคนจะเป็นนักคณิตศาสตร์ สองเซ็นต์ของฉันฉันคิดว่ามันเป็นข้อบกพร่องในการออกแบบของภาษา แต่คุณไม่สามารถเปลี่ยนได้ในตอนนี้
= MOD (-4,180) = 176 = MOD (176, 180) = 176
เพราะ 180 * (-1) + 176 = -4 เหมือนกับ 180 * 0 + 176 = 176
เมื่อใช้ตัวอย่างนาฬิกาที่นี่http://mathworld.wolfram.com/Congruence.html คุณจะไม่บอกว่าช่วงเวลาการทำงานของช่วงเวลา _of_time mod cycle_length คือ -45 นาทีคุณจะบอกว่า 15 นาทีแม้ว่าคำตอบทั้งสองจะเป็นไปตามสมการพื้นฐานก็ตาม
-1
แทนที่จะn-1
เป็นเช่น) แล้วมีที่มัน
Java 8 มี Math.floorMod
แต่มันช้ามาก (การใช้งานมีหลายหน่วยงานการคูณและเงื่อนไข) เป็นไปได้ว่า JVM มีต้นขั้วที่ได้รับการปรับให้เหมาะสมภายในซึ่งจะทำให้เร็วขึ้นอย่างมาก
วิธีที่เร็วที่สุดในการทำเช่นนี้floorMod
ก็เหมือนกับคำตอบอื่น ๆ ที่นี่ แต่ไม่มีสาขาตามเงื่อนไขและมีเพียงคำตอบเดียวเท่านั้น%
op
สมมติว่า n เป็นบวกและ x อาจเป็นอะไรก็ได้:
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;
ผลลัพธ์เมื่อn = 3
:
x | result
----------
-4| 2
-3| 0
-2| 1
-1| 2
0| 0
1| 1
2| 2
3| 0
4| 1
หากคุณต้องการเพียงการแจกแจงแบบสม่ำเสมอระหว่าง0
และn-1
ไม่ใช่ตัวดำเนินการ mod ที่แน่นอนและคุณx
ไม่ได้รวมกลุ่มไว้ใกล้0
ๆ สิ่งต่อไปนี้จะเร็วยิ่งขึ้นเนื่องจากมีความขนานในระดับคำสั่งมากขึ้นและการ%
คำนวณช้าจะเกิดขึ้นควบคู่ไปกับอีก ชิ้นส่วนเนื่องจากไม่ได้ขึ้นอยู่กับผลลัพธ์ของมัน
return ((x >> 31) & (n - 1)) + (x % n)
ผลลัพธ์ข้างต้นกับ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
หากอินพุตเป็นแบบสุ่มในช่วงเต็มของ int การแจกแจงของทั้งสองโซลูชันจะเหมือนกัน หากคลัสเตอร์อินพุตใกล้ศูนย์จะมีผลลัพธ์น้อยเกินไปn - 1
ในโซลูชันหลัง
นี่คือทางเลือก:
a < 0 ? b-1 - (-a-1) % b : a % b
ซึ่งอาจเร็วกว่าสูตรอื่น [(a% b + b)% b] หรือไม่ก็ได้ แตกต่างจากสูตรอื่นคือประกอบด้วยสาขา แต่ใช้การดำเนินการโมดูโลน้อยกว่าหนึ่งรายการ อาจเป็นไปได้ว่าคอมพิวเตอร์สามารถทำนาย <0 ได้อย่างถูกต้อง
(แก้ไข: แก้ไขสูตร)