小结模(%)运算 对 四则运算的封闭性(除法!)

转载一篇日志,写的挺好的,以后留着自己用



首先想说的是, a%b. 一般都是a>0,b>0 或 a<0, b>0. 其它情况就不要考虑了。 下面说明了为这么只需要考虑这两种情形。
其次,本文总结了模运算对加法、减法、乘法的封闭性。讨论是除法与模运算之间的关系,从而得到一个实用的公式。
========================正文(精华在文末...)========================
在数学中,我们做取模运算(a%b)都是假设a,b>0的.但在编程处理时,我们经常会碰到a<0,b<0的情况, 而且计算机自己处理取模运算时,与我们数学求出来的结果还不一样 ( 我们想要的结果就是按数学方法计算出来的), 所以要搞清楚计算机求出来的结果与我们想要的结果之间的联系!!
1.先只考虑a<0的情况 (b>0)
a=-106 b=105 数学上: a % b = 104 计算机: a % b = -1
a=-312 b=105 数学上: a % b = 3 计算机: a % b = -102
在计算机中(使用VC++)做取模运算时:
#include <stdio.h>
int main()
{
int x;
int y = 105;
for (x=110; x>=-110; x--)
printf("%d %% %d = %d\n", x, y, x%y);
return 0;
}

经过大量测试发现:
若我们不能保证a一定大于0时,结果为负时,我们加上一个b就与我们数学中求
得的结果是一样的. 参加上面介绍的第二个例子 a = -312时
2.不需要考虑b<0, 因为计算机是把它当成-b来处理,所以与b>0一样
#include <stdio.h>
int main()
{
int x;
int y = -5;
for (x=10; x>=-10; x--)
printf("%d %% %d = %d\n", x, y, x%y);
printf("=============================\n");
y = 5;
for (x=10; x>=-10; x--)
printf("%d %% %d = %d\n", x, y, x%y);
return 0;
}
===========================

模运算有很多性质
(a+b)%n = (a%n + b%n) % n;
(a*b)%n = ((a%n)*(b%n)) % n;
(a-b)%n = (a+(-b))%n = ( (a%n) + ((-b)%n) ) % n 若结果为负,加上n即可
(a/b)%n 没有这个性质了,呵呵~~
取模运算对加法、减法、乘法都封闭,所以我们很容易计算(a+b)mod m,(a-b)mod m,(a*b)mod m。但是,要计算(a/b) mod m就不是那么容易了。 下面首先介绍一个通用公式:
(a / b) % m = ( a % (m*b)) / b --- 推导见文末
除了上面的公式,还有一些特殊的情况, eg: m和b互素的时候。
1. 当gcd(b,m) = 1, 有性质: (a/b)%m = (a*b^-1)%m, 其中b^-1是b模m的逆元.
求出b相对于m的逆元b^(-1),即b*(b^(-1)) = 1 (mod m)。有b*b^(-1) - km = 1,其中k是一整数. 用Extended Euclid算法可以求出`b^(-1)。然后计算a*b^(-1) mod m = ( (a%m) * (b^(-1)%m ) % m; 其值与(a/b) mod m相同
推导:a/b = x (mod m) --两边同乘一个数--> a = bx (mod m) ---x=b^-1a-> a = (b^-1) ba (mod m)
再利用b^-1*b = 1(mod m) . 所以可以得出 x = b^-1*a是成立的。
所以 (a/b) mod m 的解与 (a*b^-1)%m的解是一样的。 而后着可以利用模对乘法的线性性
2. 当gcd(b,m)!=1时怎么办? 此时方程`b*b^(-1) - km = 1`无整数解,求逆元的方法失效了。
----目前自己只会上面的那个通用公式来求。上面的公式推导如下(目标是求 (a/b) % m):
由于b | a, 所以a = k, 然后将k对m做带余法法,得: a = tmb+rb(其中r<m), a / b = tm + r
(a / b) % m = (tm+r) % m = r, 现在目标就是r。
我们可以等价的求出r。由于r<m, 所以rb<mb 所以 a % mb = rb, 然后除以b, 也就是求出了目标r 。 即公式 (a / b) % m = (a % mb) /b 成立. 然后就可以开心的用快速模幂了……但通用公式也面临一个问题: 当m*b很大时,快速模幂不能直接使用了? 相关的题目见:
http://acm.fzu.edu.cn/contest/cproblem.php?cid=1073&pid=1
Given A,B,C, You should quickly calculate the result of A^B mod C. (1<=A,B,C<2^63).
A^B mod C:
---------呵呵,刚刚解决这个题,两次二分(多出来的一次二分是解决(A*B)%C的溢出问题)。这也说明通用公式还是有很多用武之地的,只要m*b<2^63 -- (当然,更大时怎么办,高精度么?待整理)

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值