两个负数相除的余数,对负数取余数的规则是,两个负数相除的余数,对负数取余数的规则叫什么
不同语言中的负余数问题
问题的出现
偶然在leetcode上看到这样一个问题:
给定一个32位有符号整数,整数的反数位。
翻译成中文是:
给定一个32位有符号整数,从低位到高位反向输出整数,例如:
输入:1230
返回:321
题目很简单,有很多种实现方式。我用了大概十分钟在脑子里想到了最好的解决方案,然后用电脑做了实验:
int reverse_num(int x,int res)
{
如果(!x)返回结果;
return reverse_num(x/10,(RES * 10 x));
}
int main()
{
int val=0;
val=reverse_num(-9870,val);
标准输出
}
输出结果:
-789
求解!其实也可以用循环高效实现。为什么要用递归?因为递归总能写出简洁漂亮的代码(事实上,要安装X.).
作为一种习惯,我将再次用python实现它,使用相同的代码结构:
定义反向(x,res):
如果x==0:
返回资源
反向返回(x/10,(res*10 x))
def main():
编号=-9870
res=0
val=reverse(数字,分辨率)
打印值
输出结果:
RuntimeError:超过了最大递归深度
什么****!
我抬起颤抖的小手,移动屏幕一行行检查代码,发现没有任何问题。
我以为大局已定,结果被极限杀了。当然,我不能就这么算了,于是我启动了调试模式。
毕竟程序很简单,问题很快就被发现了:
打印-987/10
-99
印刷-99/10
-10
2010年10月印刷
-1
印刷-1/10
-1
印刷-1/10
-1
印刷-1/10
-1
在这一点上,观众先生们也应该看到了问题。从上面的运行结果来看-987/10的结果实际上是-99而不是-98,-1/10的结果是-1,再次执行-1/10的结果当然是-1,递归的退出条件是x=0,导致递归无限执行,所以堆栈溢出。
问题的解决方法
根据资料显示,目前主流的划分方法有两种:截断划分和Floored划分。这两种方法在处理正除法时是一致的,但在处理负除法时略有不同。
首先需要明白,对于整数的除法,这个公式是满足的:
m=q*n r
m是红利。
n是除数。
r是余数
q是商
m,n,q和r都是整数。
即:
14=3*4 2
用4除4得3,剩下2。
这不是标准吗?那为什么会有差异呢?
当然,正整数的除法是没问题的,但是如果遇到负数的除法,比如
-8/5
有两种结果,即:
-8=5*(-1) (-3)
在这种情况下,商是-1,余数是-3。
或者:
-8=5*(-2) 2
在这种情况下,商是-2,余数是2。
两种划分的不同导致了上述不同语言的不同标准。
法定标准
官方资料显示,C89和C98标准中对此没有规定,将实现留给编译器决定。这会导致什么?就是我们常说的实践出真知。在这种情况下,你可能会得到一个错误的结果!
不管你的编译器是用C/C标准还是python标准,你的结论都是单一标准,写出来的代码在另一个编译器下不可移植。
想
这就引发了一个博主的思考:有时候,在研究这类计算机问题的时候,不能只把某个平台上的实验结果作为标准答案,这是有失偏颇的。编译器工具链(脚本解释器)往往有多个版本,但单个平台无法覆盖所有编译器(脚本解释器)版本,也许我们只是选择最通用的版本,或者选择几个分歧版本中的一个。
统一标准
在C99标准中,明确定义了‘向零截断’,即舍入到0。在这种模式下,在负整数除法中,当商为负时,小数部分向接近0的方向四舍五入,即舍弃小数部分,而C和Java遵循C的方式,也是同样的例子:
-8/5=-1.6
商是-1.6,但因为是整数除法,小数部分四舍五入为0,商是-1,所以余数是-3,即:
-8=5*(-1) (-3)
然而,在python中,小数部分是向1的方向舍入的。例如:
-8/5=-1.6
商是-1.6,但因为是整数除法,小数部分四舍五入为1,商是-2,所以余数是2,也就是:
-8=5*(-2) 2
我们对除法在两种不同语言中的实现有了基本的了解,但事情就到此为止了吗?不要!
以上讨论只是
正整数/正整数
负整数/正整数
还有两种情况。怎么能错过他们呢?
负整数/负整数
正整数/负整数
对于负整数/负整数除法,两种除法有区别吗?
由于C99之后统一了C有符号整数除法的标准,所以我们还是可以选择在电脑上运行代码来检查。
正整数/负整数
代码片段c:
int div=8/-5;
int mod=8%-5;
int div 1=5/-8;
int mod1=5%-8;
标准输出
标准输出
运行结果:
8/-5=-1
8%-5=3
5/-8=0
5%-8=5
Python代码片段:
打印“% s % d”%( 8/-5=,8/-5)
打印“% s % d”%( 8%-5=,8%-5)
打印“% s % d”%( 5/-8=,5/-8)
打印“% s % d”%( 5%-8=,5%-8)
运行结果:
8/-5=2
8%-5=-2
5/-8=-1
5%-8=-3
以正整数/负整数为例,C/C和python的标准如上所述。当商为负时,商的小数部分被逐一四舍五入,导致不同的结果。
负整数/负整数
C/C代码片段:
int div=-8/-5;
int mod=-8%-5;
int div 1=-5/-8;
int mod1=-5%-8;
标准输出
标准输出
运行结果:
-8/-5=1
-8%-5=-3
-5/-8=0
-5%-8=-5
Python代码片段:
打印“% s % d”%(-8/-5=,-8/-5)
打印“% s % d”%(-8%-5=,-8%-5)
打印“% s % d”%(-5/-8=,-5/-8)
打印“% s % d”%(-5%-8=,-5%-8)
运行结果:
-8/-5=1
-8%-5=-3
-5/-8=0
-5%-8=-5
两种语言输出结果一样,很多盆友开始有点迷茫。不是标准不一样,小数部分四舍五入方向不一样吗?
如果你仔细看看上面的例子,你会发现一个先决条件。当商为负时,舍入有差异。但是,如果这里的商是正的,比如-5/-8=0.625,遵循正整数的整除法则(别忘了!两种语言对正整数的处理是一致的):
如果商为0,则:
-5=0*(-8) (-5)
余数是-5
简单总结
Python和C/C /JAVA有两个负商除法的标准。在python中,商的小数部分被四舍五入,而在C/C /JAVA中,商的小数部分被丢弃。(网上资料显示,Ruby的处理和python是一个标准。博主没测试过。有兴趣的朋友可以试试。)
好了,关于不同语言有符号整数除法的讨论到此结束。如果朋友们对此有什么疑问,或者发现文章有什么错误,欢迎留言。
原创博客,转载请注明出处!
祝大家早日实现项目,bug不粘你。