模运算(求余)的坑

Last Updated: 2023-11-29 02:23:43 Wednesday

-- TOC --

反反复复被这个细节困扰,关于模运算,现在我的理解是:Python的模运算应该是符合数学定义的;而C语言,或者x86平台的模运算,有个迷人的与Python不一样的细节。这里说的模运算,就是%运算,求余。下面只说C语言部分:

在x86平台下,-27 % 10 = -7。对,结果是负数!

原因:x86平台计算%时,使用idiv指令,查阅手册,看到一句话:

The sign of the remainder is always the same as the sign of the dividend, and the absolute value of the remainder is less than the absolute value of the divisor.

OK,不用再困扰了,人家就是这样子定义和实现的!

idiv指令,余数的符号与被除数相同,余数的绝对值小于除数的绝对值。

现在也清楚了,27 % -10 = 7

数学中,有定义对负数进行模运算吗?...

看一段代码:

#include <stdio.h>

int main(){
    int a = -27;
    int b = 10;
    int c = a % b;
    printf("%d\n", c);  // -7
    return 0;
}

对应的汇编如下:

.LC0:
        .string "%d\n"
main:
        push    rbp
        mov     rbp, rsp
        sub     rsp, 16
        mov     DWORD PTR [rbp-4], -27
        mov     DWORD PTR [rbp-8], 10
        mov     eax, DWORD PTR [rbp-4]
        cdq
        idiv    DWORD PTR [rbp-8]
        mov     DWORD PTR [rbp-12], edx
        mov     eax, DWORD PTR [rbp-12]
        mov     esi, eax
        mov     edi, OFFSET FLAT:.LC0
        mov     eax, 0
        call    printf
        mov     eax, 0
        leave
        ret

就是一条idiv指令,然后取存放余数的寄存器。That's it...

如果计算存在unsigned类型,会使用div指令!integer promotion!

C语言也被称为portable assembly language,C语言的这一层抽象很薄,但却非常关键,C语言的计算与直接用汇编语言计算,结果几乎一样。这是C语言的定位!理解这一点很重要,这也解释了C语言会继续保持自身的简单优雅,不会包含更高层次的抽象,绝不可能有GC功能...

LeetCode第7题,反转整数,我在最后实现的一个C语言解法,利用了这个特性!

本文链接:https://cs.pynote.net/sf/c/202310151/

-- EOF --

-- MORE --