c语言的取模运算

2019-04-13 20:53发布

我们对C的%运算知多少呢?
当是正整数时,可能大家都知道。例如:5%3等于2, 3%5等于3。
当存在负数时呢?先看看例子:
例一:
int main()
{      int x;
     x = -6%5; printf("%2d/n",x);   
     x = 6%-5; printf("%2d/n",x);   
     x = 1%-5; printf("%2d/n",x);   
     x = -1%-5; printf("%2d/n",x);
     x = -6%-5; printf("%2d/n",x);   
}
运行结果为:
-1
1
1
-1
-1
例二:
#include
int main() {      int x;
     x = 5%-6; printf("%2d/n",x);   
     x = -5%6; printf("%2d/n",x);   
     x = 4%5;   printf("%2d/n",x);   
     x = -4%-5; printf("%2d/n",x);
     x = -5%-6; printf("%2d/n",x);   
}
运行结果为:
5
-5
4
-4
-5 你看出规律了吗?我帮你总结一下:
余数的定义:当被除数不够整除时余下的数。 当都是正整数时:
除法实际可转化为减数,不够减时剩下的就是余数。
例如:12%5
           12-5-5
            2
当存在负数时: x%y
   i. 当异号时:
                 if |x|>|y|
                    result: x+y
                 else 
                    result: x
             例:
                -6% 5等于-1
                 6%-5等于 1
                 5%-6等于 5
                -5% 6等于 -5
   ii. 当同号时:
                if |x|>|y|
                    result: x-y
                 else 
                    result: x
             例:
               -1%-5等于-1
                -6%-5等于-1
                -4%-5等于-4
                -5%-6等于-5
   相信当你记住这个规律后,再遇到这种问题,你不用思考就可以回答出来。
但你一定不会满意,因为这不是你想要的结果,你一定觉得还有更深层的
原因。如果你感兴趣,请接着看:
例三:
#include
int main()
{      int x;
     x = -6/5; printf("%2d/n",x);   
     x = 6/-5; printf("%2d/n",x);   
     x = 1/-5; printf("%2d/n",x);   
     x = -1/-5; printf("%2d/n",x);
     x = -6/-5; printf("%2d/n",x);   
}
运行结果:
-1
-1
0
0
1
例四:
#include
int main()
{      int x;
     x = 5/-6; printf("%2d/n",x);   
     x = -5/6; printf("%2d/n",x);   
     x = 4/5;   printf("%2d/n",x);   
     x = -4/-5; printf("%2d/n",x);
     x = -5/-6; printf("%2d/n",x);   
}
运行结果:
0
0
0
0
0
   这两个例子我想大家都觉得很简单,但简单并不代表它没价值,
特别是它和其它事物联系其来时你才会注意到。
“/”在我们这些程序中代表整除,它符合除法法则,异号抵消。
再看看我们余数的定义
                   整除“余”下的“数”。
则有:余数=被除数-商*除数
商就是我们整除的结果。
看例子:
eg1:
        (-6%5) = -6 - (-6/5)*5
        (-6%5) = -6 - (-1)*5
        (-6%5) = -6 - (-5)
        (-6%5) = -6+5
        (-6%5) = -1
eg2:
        (5%-6) =   5 - (5/-6)*(-6)
        (5%-6) =   5 - (0)*(-6)
        (5%-6) =   5 - 0
        (5%-6) =   5
eg3:
        (-5%-6)= -5 - (-5/-6)*(-6)
        (-5%-6)= -5 - (0)*(-6)
        (-5%-6)= -5 - 0
        (-5%-6)= -5
eg4:
        (6%-5) =   6 - (6/-5)*(-5)
        (6%-5) =   6 - (-1)*(-5)
        (6%-5) =   6 - 5
        (6%-5) =   1
到现在为止,你还有什么疑惑?
但我还是有点不明白,这是数学中的定义吗?
我查了一下《Concrete Mathematics》,请看原文:
摘之 P82
------------------
3.4 ‘MOD': THE BINARY OPERATION
     The quotient of n divided by m is [n/m],when m and n are positive
integers. It's handy to have a simple notation also for the remainder
of this division, and we call it 'n mod m', The basic formula
     n = m[n/m]+ n mod m
//NOTE:"m[n/m]" is quotient, "n mod m" is remainder
tells us that we can express n mod m as n-m[n/m] .We can generalize this
to megative integers, and in fact to arbitrary real numbers:
     x mod y = x - y[x/y], for y!=0.

--------------------
从文中可能看出,数学中的 余数(remainder) 其实就是 取模(mod),即:
     x mod y = x%y
     x%y     = x - y[x/y], for y!=0.
数学中的余数概念和我们的计算机中的余数概念一致,但实现却不一致。
其中 [x/y] 代表的是 x/y 的最小下界。
例:
     -3 mod 2         = -3 - 2*[-3/2]
                            = -3 - 2*[-1.5]
                            = -3 - 2*(-2)
                            = -3 + 4
                            = 1
而我们的计算机是怎么做的呢:
             -3%2        = -3 - 2*(-3/2)
                             = -3 - 2*(-1)
                              = -3 - (-2)
                              = -1
所以计算机中的取余实际上是:
       x%y = x - y(x/y), for y!=0.
   这就是二者的区别。这个区别,对于正数,二者计算出的结果是相等的,但是负数就不相等了。这就意味着,如果以后在使用数学中余数相关定理的时候,要注意计算机中余数的计算和数学定义不是完全一致的,所以在计算机上,对于负数,数学定理并不完全适用。当然,对于正数,二者是没有区别的。至于为什么计算机上要这么实现,我想恐怕还是历史原因,最早的计算机如果这样计算除法(取余是靠除法来完成的),那么就涉及到浮点数的计算以及取下界,这样,将比较大的降低效率,所以实现成了这样的方式,一直沿用至今。