C/C++编程问题中%运算符的含义与处理方式

相信熟悉 C/C++的读者对%运算符一定不会陌生,我们将其称为求模运算符,通俗的讲即求一个数被另一个数除后剩余的余数。

%运算符的用法非常简单,我们用形如 a % b 的语句来调用该运算符。其中变量 a,b 必须为整型变量,例如 int、short 等,而不能为浮点数。且 b 变量必须为非零值,若出现模零错误,程序会因为该异常意外终止。在评判系统中表现为评判系统给出了运行时错误,程序未运行完成就异常终止。

以 a % b 语句为例,我们先不加说明的指出该运算的特点。其运算在行为上好像是按如下步骤进行的,首先计算出 a 的绝对值被 b 的绝对值除所得的余数, 再使该余数的符号与 a 保持一致。即若 a 为正数,则该表达式结果必为非负数(可 能为 0);若 a 为负数,则表达式结果必为非正数(可能为 0)。而表达式结果与 b的符号没有直接关系,即a%-b 与 a%b的结果相同。

我们注意到,通过求模运算符求得的余数存在着负数的可能。而这与数论中关于余数的定义是不相符的。数论指出,余数的取值范围为从 0 到除数减 1,即 在 a % b 表达式中,其符合数论规定的的结果取值范围应是 0 到 b - 1。%运算符的运算特性仅保证余数的绝对值在如上所述的范围内,而不保证不会出现负数, 出现负余数也为我们下一步操作带来诸多不便。那么我们必须保证表达式求得的余数在数论定义的区间范围内。相信很多读者心中都有答案,我们只需在该负的余数上再加上除数再对除数求一次余即可。那么它的原理又是如何的呢?我们来看下两式:

r = a%b;
a = k *b + r;

r 即为我们要求的余数,它是由第一式求得的。同时它应符合第二式中关于余数的原始定义,即 a 将等于某个整数与 b 的积再加上余数 r,由于 C/C++的% 算符特点,当 a 为负数时 r 很可能出现负数(或为 0),我们为了得到正确范围内 的余数,我们可以对该式作如下变形(这里假设 b 大于 0,否则取绝对值):

a = (k −1)*b + r + b;

若 r 非零,该式同样符合关于余数的相关定义,但是它的余数部分(r + b) 将不再为负数,而是落在我们之前讨论的、数论规定的范围[0,b-1]内,即由 0 至 b-1。而这个符合我们要求的新余数即为原负余数加上 b,我们正是利用该方法来使余数落入所需的区间内。但是读者还需特别注意,即使被除数为负数,余数也 是有可能为 0 的(刚好整除),那么假如我们与对待其他负余数一样为其加上余 数以期其能够落入我们需要的区间内,这将会适得其反(将会使余数等于 b)。 所以我们可以统一的对取得的余数加上除数后再对该和求模,即:

r'=(r+b)%b;

这样做,不仅能对可能出现的负余数做适当的修正,同时对出现的零和正余 数也不会改变他们的值。

另外,我们也可以顺便来看一下为什么在%运算中余数的值看起来好像与除数的符号无关。我们假设 b 为正数,我们利用 r = a % b 求得的余数 r 将会满足 下式:

a = k *b + r;

其中 r 绝对值的取值范围为从 0 到 b-1,其符号保持与 a 一致(除非 r 为 0)。

若此时,我们利用 r = a % -b 来求得的余数 r'又会满足下式

a = k'*(−b) + r';

同样,其中 r 的取值范围为从 0 到 b-1,其符号保持与 a 一致。比较两式我 们即能发现,当 k' 等于-k 时两式成立,且 r'与 r 相同。这就是为什么我们用% 运算符求得的余数看起来好像与除数的符号无关的原因。

最后我们总结一下%运算的数学解释,以式 r = a % b 为例,其所求得的 r将满足下式:

a = k *b + r

其中 k 为某整数,r 的绝对值取值范围是[0,b-1],其符号将与 a 保持一致,

除非其为 0。这就是我们需要了解的%运算符的工作特点。

另外%运算还具有如下运算规律,牢记这些规律将帮助我们有效的避免大数求模中的溢出问题,关于大数求模,在后文中会有所涉及。

(a*b)%c = (a%c*b%c)%c;

(a + b)%c = (a%c + b%c)%c;

参考:wdjs

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值