วิธีเขียนโค้ดตัวดำเนินการ modulo (%) ใน C / C ++ / Obj-C ที่จัดการตัวเลขติดลบ


87

สัตว์เลี้ยงตัวหนึ่งของฉันเกลียดภาษาที่ได้รับ C (ในฐานะนักคณิตศาสตร์) ก็คือ

(-1) % 8 // comes out as -1, and not 7

fmodf(-1,8) // fails similarly

ทางออกที่ดีที่สุดคืออะไร?

C ++ ช่วยให้แม่แบบและตัวดำเนินการทำงานมากเกินไป แต่ทั้งสองอย่างนี้เป็นน้ำที่ขุ่นมัวสำหรับฉัน ตัวอย่างที่ได้รับอย่างซาบซึ้ง


1
ฉันไม่คิดว่านี่เป็นการ "ซ้ำ" ของstackoverflow.com/questions/828092/…ภายใต้คำจำกัดความอย่างเป็นทางการ ไม่เป็นความจริงที่คำตอบของคำถามนี้สามารถรวมเข้ากับคำถามนั้นได้เพราะคำถามนี้ถามเกี่ยวกับโมดูลัสเท่านั้นไม่ใช่การหารด้วย แต่ฉันคิดว่าคำถามนี้ครอบคลุมคำถามนั้นจึงใกล้เคียง คำตอบของฉันมีอยู่แล้ว FWIW
Steve Jessop

บางทีควรแยกเธรดนั้นเนื่องจากถามคำถามแยกกันสองคำถาม วิธีที่ดีที่สุดในการทำเช่นนั้นอาจเป็นการถามคำถามแยกกันอีกครั้งแล้วชี้ไปที่คำตอบนั้น ฉันจะปล่อยให้คนที่เข้าใจกลไกของเว็บไซต์นี้ดีขึ้น
P i

3
@Pi owhere ถูก%กล่าวถึงเป็นแบบโมดูโล ... มันเป็นส่วนที่เหลือ
obataku

1
นี่คืออีกหัวข้อหนึ่งที่ "ซ้ำกัน" ของ: stackoverflow.com/questions/1082917/…เพื่อใช้อ้างอิงใน%ปัญหานี้เท่านั้น
leetNightshade

หากคุณกำลังหารเพียงสองพลังคุณควรใช้และ:(-1) & 8 == 7
เฮนริคัสโวลต์

คำตอบ:


75

(-1) % 8 == -1แรกของทั้งหมดที่ฉันต้องการที่จะทราบว่าคุณไม่สามารถแม้แต่จะพึ่งพาความจริงที่ว่า (x / y) * y + ( x % y) == xสิ่งเดียวที่คุณสามารถพึ่งพาคือว่า อย่างไรก็ตามไม่ว่าจะเป็นหรือไม่ที่เหลือเป็นลบคือการดำเนินการตามที่กำหนดไว้

ทำไมต้องใช้เทมเพลตที่นี่ การโอเวอร์โหลดสำหรับ ints และ longs จะทำ

int mod (int a, int b)
{
   int ret = a % b;
   if(ret < 0)
     ret+=b;
   return ret;
}

และตอนนี้คุณสามารถเรียกมันว่า mod (-1,8) และดูเหมือนว่าจะเป็น 7

แก้ไข: ฉันพบข้อบกพร่องในรหัสของฉัน มันจะใช้ไม่ได้ถ้า b เป็นลบ ดังนั้นฉันคิดว่าสิ่งนี้ดีกว่า:

int mod (int a, int b)
{
   if(b < 0) //you can check for b == 0 separately and do what you want
     return -mod(-a, -b);   
   int ret = a % b;
   if(ret < 0)
     ret+=b;
   return ret;
}

อ้างอิง: C ++ 03 วรรค 5.6 ข้อ 4:

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


2
@Ohmu: ใช่อยู่ในมาตรฐาน C ++ <quote> สำหรับอินทิกรัลโอเปอเรเตอร์ / ตัวดำเนินการจะให้ผลหารพีชคณิตโดยมีส่วนที่เป็นเศษส่วนทิ้งไป ถ้าผลหาร a / b แทนได้ในประเภทของผลลัพธ์ (a / b) * b + a% b เท่ากับ a </quote>
Ben Voigt

5
-1. เป็นเวลา 11 ปีแล้วที่มีการกำหนดการใช้งานนี้ ISO 9899: 1999 กำหนดไว้และน่าเสียดายที่เลือกคำจำกัดความที่ไม่ถูกต้อง
R .. GitHub STOP HELPING ICE

3
@Armen: คุณสามารถลบเชิงอรรถได้โดยสะดวก ... การหารจำนวนเต็มเป็นไปตามกฎที่กำหนดไว้ในมาตรฐาน ISO Fortran, ISO / IEC 1539: 1991 ซึ่งผลหารจะปัดเศษเป็นศูนย์เสมอ มาตรฐาน C ++ ใหม่อัปเกรดพฤติกรรมนี้จาก "ที่ต้องการ" เป็นบังคับเช่นเดียวกับ Fortran และ C.
Ben Voigt

2
@Armen: สเป็คเก่าเสีย แต่การแตกหักนั้นแตกต่างจากปัญหาการเข้าสู่ระบบและมันง่ายที่จะพลาดจนกว่าคุณจะดูถ้อยคำใหม่ C ++ 03 ไม่มี "ถ้าผลหาร a / b แสดงได้ในประเภทของผลลัพธ์" ซึ่งทำให้เกิดปัญหาสำหรับINT_MIN / -1(ในการใช้งานส่วนเสริมสองรายการ) ภายใต้ข้อมูลจำเพาะเก่า-32768 % -1อาจต้องประเมินเป็น-65536(ซึ่งยังไม่อยู่ในช่วงของประเภท 16 บิต yuck!) เพื่อให้ตัวตนคงอยู่
Ben Voigt

1
re "อย่างไรก็ตามไม่ว่าส่วนที่เหลือจะเป็นค่าลบหรือไม่ก็ตามจะมีการกำหนดการนำไปใช้งาน", C ++ 11 รับรองว่าการหารจำนวนเต็มจะปัดเศษเป็น 0
ไชโยและ hth - Alf

13

นี่คือฟังก์ชัน C ที่จัดการค่าจำนวนเต็มบวกหรือค่าลบหรือเศษส่วนสำหรับทั้งสอง OPERANDS

#include <math.h>
float mod(float a, float N) {return a - N*floor(a/N);} //return in range [0, N)

นี่เป็นวิธีการแก้ปัญหาที่สวยงามที่สุดจากมุมมองทางคณิตศาสตร์ อย่างไรก็ตามฉันไม่แน่ใจว่ามีประสิทธิภาพในการจัดการจำนวนเต็มหรือไม่ บางครั้งข้อผิดพลาดของทศนิยมจะคืบคลานเข้ามาเมื่อแปลง int -> fp -> int

ฉันใช้รหัสนี้สำหรับ non-int s และฟังก์ชันแยกต่างหากสำหรับ int

หมายเหตุ: ต้องดักจับ N = 0!

รหัสผู้ทดสอบ:

#include <math.h>
#include <stdio.h>

float mod(float a, float N)
{
    float ret = a - N * floor (a / N);

    printf("%f.1 mod %f.1 = %f.1 \n", a, N, ret);

    return ret;
}

int main (char* argc, char** argv)
{
    printf ("fmodf(-10.2, 2.0) = %f.1  == FAIL! \n\n", fmodf(-10.2, 2.0));

    float x;
    x = mod(10.2f, 2.0f);
    x = mod(10.2f, -2.0f);
    x = mod(-10.2f, 2.0f);
    x = mod(-10.2f, -2.0f);

    return 0;
}

(หมายเหตุ: คุณสามารถรวบรวมและเรียกใช้งานได้โดยตรงจาก CodePad: http://codepad.org/UOgEqAMA )

เอาท์พุต:

fmodf (-10.2, 2.0) = -0.20 == ล้มเหลว!

10.2 mod 2.0 = 0.2
10.2 mod -2.0 = -1.8
-10.2 mod 2.0 = 1.8
-10.2 mod -2.0 = -0.2


น่าเสียดายที่สิ่งนี้ใช้ไม่ได้กับจำนวนเต็ม พวกเขาจะต้องถูกแปลงเป็นทศนิยมก่อนการหารเพื่อให้คุณใช้งานfloor()ได้ นอกจากนี้คุณอาจสูญเสียความแม่นยำเมื่อคุณแปลงเป็น float: ลอง(float)1000000001/3แล้วคุณจะประหลาดใจกับผลลัพธ์!
cmaster - คืนสถานะ monica

9

ฉันเพิ่งสังเกตว่า Bjarne Stroustrup ติดป้ายกำกับ%เป็นตัวดำเนินการส่วนที่เหลือไม่ใช่ตัวดำเนินการโมดูโล

ฉันจะพนันได้เลยว่านี่เป็นชื่อที่เป็นทางการในข้อกำหนด ANSI C & C ++ และการใช้คำศัพท์ในทางที่ผิดมีใครรู้บ้างไหม

แต่ถ้าเป็นกรณีนี้ฟังก์ชัน fmodf () ของ C (และอาจเป็นฟังก์ชันอื่น ๆ ) จะทำให้เข้าใจผิดได้มาก ควรติดป้ายกำกับว่า fremf () ฯลฯ


1
มาตรฐาน C11 (หรือแบบร่างสาธารณะสุดท้ายที่แน่นอน) กล่าวถึง "โมดูโล" หกครั้ง แต่เฉพาะในส่วนที่เกี่ยวข้องกับการเป็นตัวแทนของประเภทต่างๆ ไม่มีการพูดถึง "โมดูโล" ที่เกี่ยวข้องกับตัวดำเนินการส่วนที่เหลือ ( %) สักครั้ง
Nisse Engström

7

ฟังก์ชันทั่วไปที่ง่ายที่สุดในการค้นหาโมดูโลเชิงบวกคือนี่ - มันจะใช้ได้กับทั้งค่าบวกและค่าลบของ x

int modulo(int x,int N){
    return (x % N + N) %N;
}

6

สำหรับจำนวนเต็มนี่เป็นเรื่องง่าย แค่ทำ

(((x < 0) ? ((x % N) + N) : x) % N)

โดยที่ฉันคิดว่านั่นNเป็นบวกและเป็นตัวแทนในประเภทของx. คอมไพเลอร์ที่คุณชื่นชอบควรจะปรับแต่งสิ่งนี้ให้เหมาะสมเพื่อให้มันจบลงด้วยการดำเนินการ mod เพียงครั้งเดียวในแอสเซมเบลอร์


3
ไม่ได้ผล: int x=-9001; unsigned int N=2000;ให้ 2295 ไม่ใช่ 999
Hubert Kario

1
@HubertKario อาจจะตรวจสอบอีกครั้ง? ไม่มีทางที่บางสิ่งที่ modulo 2000 ให้ 2295 คุณต้องทำผิดพลาด
sam hocevar

2
@SamHocevar: ฉันคิดว่าปัญหาที่นี่คือกฎการส่งเสริมจำนวนเต็ม C แปลก ๆ ลงนามส่งเสริมเป็นไม่ได้ลงนามและส่งเสริมค่าจำนวนเต็มลงนามที่ไม่ได้ลงชื่อเพื่อเรียกใช้พฤติกรรมที่ไม่ได้กำหนดใน C.
datenwolf

1
ผมเชื่อว่าง่ายมาก (และมีประสิทธิภาพมากขึ้น) (x < 0) ? (x % N + N) : (x % N)รูปแบบจะเป็น:
Chris Nolet

3

ทางออกที่ดีที่สุด¹สำหรับนักคณิตศาสตร์คือการใช้ Python

การโอเวอร์โหลดตัวดำเนินการ C ++ มีส่วนเกี่ยวข้องเพียงเล็กน้อย คุณไม่สามารถโอเวอร์โหลดตัวดำเนินการสำหรับชนิดในตัวได้ สิ่งที่คุณต้องการมีเพียงแค่ฟังก์ชั่น แน่นอนคุณสามารถใช้ C ++ templating เพื่อใช้ฟังก์ชันนั้นสำหรับทุกประเภทที่เกี่ยวข้องด้วยโค้ดเพียง 1 ชิ้น

ไลบรารี C มาตรฐานจัดเตรียมfmodหากฉันจำชื่อได้ถูกต้องสำหรับประเภทจุดลอยตัว

สำหรับจำนวนเต็มคุณสามารถกำหนดเทมเพลตฟังก์ชัน C ++ ที่จะคืนค่าส่วนที่ไม่เป็นลบเสมอ (ตรงกับการหารยูคลิด) เป็น ...

#include <stdlib.h>  // abs

template< class Integer >
auto mod( Integer a, Integer b )
    -> Integer
{
    Integer const r = a%b;
    return (r < 0? r + abs( b ) : r);
}

... และเขียนmod(a, b)แทนa%bแทน

นี่คือประเภท Integerจะต้องเป็นประเภทจำนวนเต็มที่ลงนาม

หากคุณต้องการให้พฤติกรรมทางคณิตศาสตร์ทั่วไปโดยที่เครื่องหมายของเศษเหลือเหมือนกับเครื่องหมายของตัวหารคุณสามารถทำได้เช่น

template< class Integer >
auto floor_div( Integer const a, Integer const b )
    -> Integer
{
    bool const a_is_negative = (a < 0);
    bool const b_is_negative = (b < 0);
    bool const change_sign  = (a_is_negative != b_is_negative);

    Integer const abs_b         = abs( b );
    Integer const abs_a_plus    = abs( a ) + (change_sign? abs_b - 1 : 0);

    Integer const quot = abs_a_plus / abs_b;
    return (change_sign? -quot : quot);
}

template< class Integer >
auto floor_mod( Integer const a, Integer const b )
    -> Integer
{ return a - b*floor_div( a, b ); }

…ด้วยข้อ จำกัด เดียวกันIntegerนั่นคือเป็นประเภทที่เซ็นชื่อ


¹เนื่องจากการหารจำนวนเต็มของ Python จะปัดเศษเข้าหาอินฟินิตี้เชิงลบ


ดูเหมือนว่าโค้ดของคุณจะมีข้อผิดพลาดเหมือนกับของฉันก่อนที่จะทำการแก้ไข เกิดอะไรขึ้นถ้า b เป็นลบ? :)
Armen Tsirunyan

1
@ อาร์เมน: ขอบคุณ! แต่ฉันขี้เกียจเกินไปที่จะแก้ไขเพียงแค่นั้น ... :-)
ไชโยและ hth - Alf

@ArmenTsirunyan: rผลลัพธ์ต้องทำให้a= r + b*(a/b)true ไม่ว่าการหารจำนวนเต็มจะถูกนำไปใช้อย่างไรb*somethingก็เป็นผลคูณของb. สิ่งนี้ทำให้rผลลัพธ์ของโมดูโลที่ถูกต้องแม้ว่าจะเป็นลบก็ตาม คุณสามารถเพิ่ม abs ( b) ลงไปได้และยังคงเป็นผลลัพธ์ของโมดูโลที่ถูกต้อง
ไชโยและ hth - Alf

2
@downvoters: คำตอบนี้ยังคงถูกต้องในขณะที่ "โซลูชัน" ที่เลือกตอนนี้มีคำอธิบายที่ไม่ถูกต้องเนื่องจากการค้ำประกันใหม่ใน C ++ 11 มันค่อนข้างน่าขันที่จะลงคะแนนคำตอบที่ยังถูกต้อง ไม่มีเหตุผลใดที่จะต้องถือว่าบุคคลที่เชื่อมโยงอย่างน้อย 2 คนที่มีความไม่รู้เกือบสัมบูรณ์อ่านความเห็นของคำถามนี้และการลงคะแนนที่เกี่ยวข้องกับการกระตุกเข่า โปรดอธิบายการลงคะแนนของคุณ
ไชโยและ hth - Alf

1
ผลลัพธ์ที่ต้องการทางคณิตศาสตร์คือให้เศษเหลือเป็นศูนย์หรือมีเครื่องหมายเดียวกับตัวหาร (ตัวส่วน) ถ้าตัวหารเป็นลบส่วนที่เหลือควรเป็นศูนย์หรือลบ การใช้งาน C / C ++ ส่งผลให้ส่วนที่เหลือเป็นศูนย์หรือมีเครื่องหมายเดียวกับเงินปันผล (ตัวเศษ)
rcgldr

2

โอ้ฉันเกลียดการออกแบบสำหรับสิ่งนี้ด้วย ....

คุณสามารถเปลี่ยนเงินปันผลเป็นแบบไม่ได้ลงนามในลักษณะดังนี้:

unsigned int offset = (-INT_MIN) - (-INT_MIN)%divider

result = (offset + dividend) % divider

โดยที่ออฟเซ็ตใกล้เคียงกับ (-INT_MIN) มากที่สุดของโมดูลดังนั้นการเพิ่มและการลบมันจะไม่เปลี่ยนโมดูโล โปรดทราบว่ามีประเภทที่ไม่ได้ลงชื่อและผลลัพธ์จะเป็นจำนวนเต็ม น่าเสียดายที่ไม่สามารถแปลงค่า INT_MIN ... (- offset-1) ได้อย่างถูกต้องเนื่องจากทำให้เกิดการล้นทางคณิตศาสตร์ แต่วิธีนี้มีความก้าวหน้าของการคำนวณทางคณิตศาสตร์เพิ่มเติมเพียงครั้งเดียวต่อการดำเนินการ (และไม่มีเงื่อนไข) เมื่อทำงานกับตัวแบ่งคงที่ดังนั้นจึงสามารถใช้งานได้ในแอปพลิเคชันที่คล้าย DSP

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

dividend&(divider-1)

ตัวอย่างเช่น

x mod 2 = x & 1
x mod 4 = x & 3
x mod 8 = x & 7
x mod 16 = x & 15

วิธีที่ใช้กันทั่วไปและยุ่งยากน้อยกว่าคือการใช้โมดูโลโดยใช้ฟังก์ชันนี้ (ใช้ได้กับตัวหารบวกเท่านั้น):

int mod(int x, int y) {
    int r = x%y;
    return r<0?r+y:r;
}

นี่เป็นเพียงผลลัพธ์ที่ถูกต้องหากเป็นลบ

นอกจากนี้คุณอาจหลอก:

(p% q + q)% q

สั้นมาก แต่ใช้สอง% -s ซึ่งโดยทั่วไปช้า


2

ฉันเชื่อว่าวิธีอื่นในการแก้ปัญหานี้จะใช้กับตัวแปรประเภท long แทน int

ฉันเพิ่งทำงานกับโค้ดบางตัวที่ตัวดำเนินการ% ส่งคืนค่าลบซึ่งทำให้เกิดปัญหาบางอย่าง (สำหรับการสร้างตัวแปรสุ่มที่เหมือนกันใน [0,1] คุณไม่ต้องการตัวเลขเชิงลบ :)) แต่หลังจากเปลี่ยนตัวแปรเป็น พิมพ์ยาวทุกอย่างทำงานได้อย่างราบรื่นและผลลัพธ์ตรงกับที่ฉันได้รับเมื่อเรียกใช้โค้ดเดียวกันใน python (สำคัญสำหรับฉันเพราะฉันต้องการสร้างตัวเลข "สุ่ม" เดียวกันในหลายแพลตฟอร์ม


2

นี่คือคำตอบใหม่สำหรับคำถามเก่าโดยอ้างอิงจากเอกสารวิจัยของ Microsoftและข้อมูลอ้างอิงในนั้น

โปรดทราบว่าตั้งแต่ C11 และ C ++ 11 เป็นต้นไปความหมายของการตัดทอนdivกลายเป็นศูนย์ (ดู[expr.mul]/4) นอกจากนี้สำหรับการDหารด้วยdC ++ 11 รับประกันสิ่งต่อไปนี้เกี่ยวกับผลหารqTและเศษเหลือrT

auto const qT = D / d;
auto const rT = D % d;
assert(D == d * qT + rT);
assert(abs(rT) < abs(d));
assert(signum(rT) == signum(D));

โดยที่signumแมปเป็น -1, 0, +1 ขึ้นอยู่กับว่าอาร์กิวเมนต์ของมัน <, ==,> มากกว่า 0 หรือไม่ (ดูQ&A นี้สำหรับซอร์สโค้ด)

ด้วยส่วนที่ถูกตัดทอนสัญญาณของส่วนที่เหลือจะมีค่าเท่ากับสัญญาณของเงินปันผลD-1 % 8 == -1คือ C ++ 11 ยังมีstd::divฟังก์ชันที่ส่งคืนโครงสร้างกับสมาชิกquotและremตามการแบ่งที่ถูกตัดทอน

มีคำจำกัดความอื่น ๆ ที่เป็นไปได้เช่นการแบ่งพื้นที่เรียกว่าสามารถกำหนดได้ในแง่ของการแบ่งส่วนที่ถูกตัดในตัว

auto const I = signum(rT) == -signum(d) ? 1 : 0;
auto const qF = qT - I;
auto const rF = rT + I * d;
assert(D == d * qF + rF);
assert(abs(rF) < abs(d));
assert(signum(rF) == signum(d));

ที่มีการแบ่งพื้น, สัญลักษณ์ของส่วนที่เหลือจะมีค่าเท่ากับสัญญาณของการหาร dในภาษาเช่น Haskell และ Oberon มีตัวดำเนินการในตัวสำหรับการแบ่งพื้น ใน C ++ คุณจะต้องเขียนฟังก์ชันโดยใช้คำจำกัดความข้างต้น

อีกวิธีหนึ่งคือการแบ่งยุคลิดซึ่งสามารถกำหนดได้ในแง่ของการแบ่งส่วนที่ถูกตัดทอนในตัว

auto const I = rT >= 0 ? 0 : (d > 0 ? 1 : -1);
auto const qE = qT - I;
auto const rE = rT + I * d;
assert(D == d * qE + rE);
assert(abs(rE) < abs(d));
assert(signum(rE) != -1);

ที่มีการแบ่งยุคลิดสัญลักษณ์ของที่เหลือที่เป็นบวกเสมอ


2

สำหรับวิธีการแก้ปัญหาที่ไม่ใช้กิ่งไม้และมีม็อดเพียง 1 ตัวคุณสามารถทำสิ่งต่อไปนี้ได้

// Works for other sizes too,
// assuming you change 63 to the appropriate value
int64_t mod(int64_t x, int64_t div) {
  return (x % div) + (((x >> 63) ^ (div >> 63)) & div);
}

1
/ * คำเตือน: macro mod ประเมินผลข้างเคียงของอาร์กิวเมนต์หลาย ๆ ครั้ง * /
#define mod (r, m) (((r)% (m)) + ((r) <0)? (m): 0)

... หรือคุ้นเคยกับการรับตัวแทนใด ๆ สำหรับคลาสเทียบเท่า


2
"เคยชินกับการได้ผู้แทนระดับเทียบเท่า" หรือไม่! นั่นเป็นเรื่องไร้สาระ หากคุณต้องการเพียงแค่ใช้ "ตัวแทน" rดั้งเดิม ตัว%ดำเนินการไม่มีส่วนเกี่ยวข้องกับคลาสการเทียบเท่า เป็นตัวดำเนินการที่เหลือและส่วนที่เหลือถูกกำหนดอย่างดีในเชิงพีชคณิตว่าไม่เป็นค่าลบและน้อยกว่าตัวหาร น่าเศร้าที่ C กำหนดมันผิดวิธี ยังคง +1 เพื่อให้ได้คำตอบที่ดีที่สุด
R .. GitHub STOP HELPING ICE

0

เทมเพลตตัวอย่างสำหรับ C ++

template< class T >
T mod( T a, T b )
{
    T const r = a%b;
    return ((r!=0)&&((r^b)<0) ? r + b : r);
}

ด้วยเทมเพลตนี้เศษที่เหลือที่ส่งคืนจะเป็นศูนย์หรือมีเครื่องหมายเดียวกับตัวหาร (ตัวหาร) (เทียบเท่ากับการปัดเศษไปยังอินฟินิตี้เชิงลบ) แทนที่จะเป็นพฤติกรรม C ++ ของส่วนที่เหลือเป็นศูนย์หรือมีเครื่องหมายเดียวกับเงินปันผล ( ตัวเศษ) (เทียบเท่ากับการปัดเศษเป็นศูนย์)




-1

โซลูชันนี้ (สำหรับใช้เมื่อmodเป็นค่าบวก) หลีกเลี่ยงการหารลบหรือการดำเนินการที่เหลือทั้งหมดเข้าด้วยกัน:

int core_modulus(int val, int mod)
{
    if(val>=0)
        return val % mod;
    else
        return val + mod * ((mod - val - 1)/mod);
}

-2

ฉันจะทำ:

((-1)+8) % 8 

สิ่งนี้จะเพิ่มหมายเลขหลังเข้าไปในตัวแรกก่อนที่จะทำโมดูโลให้ 7 ตามต้องการ สิ่งนี้ควรใช้ได้กับตัวเลขใด ๆ ที่ลงไป -8 สำหรับ -9 เพิ่ม 2 * 8


2
และสำหรับตัวแปรที่มีค่าเป็น-99999อย่างไร
Keith Thompson
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.