上海网站建设咨询报价,手机做服务器建网站,制作网页的图片,it行业软件开发文章目录背景探究总结被除数 dividend 用 a 表示#xff1b; 除数 divisor 用 b 表示#xff1b; 商 quotient 用 q 表示#xff1b; 余 remainder 用 rem 表示#xff1b; 模 modulo 用 mod 表示。 背景
最近在一道 Java 习题中#xff0c;看到这样的一道题#xff1a;…
文章目录背景探究总结被除数 dividend 用 a 表示 除数 divisor 用 b 表示 商 quotient 用 q 表示 余 remainder 用 rem 表示 模 modulo 用 mod 表示。 背景
最近在一道 Java 习题中看到这样的一道题
What is the output when this statement executed:
System.out.printf(-7 % 3);正整数的取余运算大家都很熟悉但是对于负数、实数的取余运算确实给人很新鲜的感觉。于是我对此进行了一些探索。我发现这里面还是颇有一点可以探索的东西的。
探究
首先看看自然数的取模运算定义1: 如果 a 和 b 是两个自然数b 非零可以证明存在两个整数 q 和 r满足 a q*b r 且0 ≤ r b。其中q 被称为商r 被称为余数。 我们计算下 (-7) % 3这个表达式正常情况下是求余数计算过程如下图所示 按自然数的除法运算规则得到商值-3余数2且完全满足上述两个关系表达式-7 (-3)*3 2 且 0 ≤ 2 3。
那么各种编程语言和计算器是否是按照这样的规则计算呢下面列举了几个程序运算的结果
程序语句输出CG 编译cout (-7) % 3;-1Java1.6System.out.println((-7) % 3);-1Python 2.6(-7) % 32百度计算器(-7) mod 32Google 计算器(-7) mod 32
可以看到结果特别有意思。这个问题是百家争鸣的。看来我们不能直接把自然数的法则用在负数上。实际上在整数范围内自然数的求余法则并不被很多人所接受大家大多认可的是下面的这个定义 2 如果 a 和 b 是两个自然数b 非零可以证明存在两个整数 q 和 r满足 a q*b r 且0 ≤ |r| |b|。其中q 被称为商r 被称为余数。 可以看到上述定义导致了有负数的求余并不是我们想象的那么简单根据上述的定义我们计算下 (-7) % 3计算过程如下图所示 注按自然数的除法运算规则定义 1商和除数的乘积要小于等于被减数才行但是很多程序并没有遵循定义 1的运算规则所以依据定义 2的规则商和除数的乘积可以大于被减数使用上图所示的技巧计算时商与除数的乘积必须接近被减数然后计算得到结果再验证定义 2的两个表达式是否成立。当然了如果你直接使用定义 2的两个表达式硬套出 p 和 r 的值也可以不过不推荐。
如上图所示可以得到两组结果
商 -3余 2商 -2余 -1
这两组结果都满足“定义 2”的表达式也就是说 2 和 -1 都是 (-7) % 3 正确的结果 所以问题来了到底余数是 2 还是 -1 呢这个问题最后会给出答案。
我们把 2 和 -1 分别叫做正余数和负余数。通常整数 a 除以整数 b 时如果得到正余数为 r1负余数为 r2那么存在这样的关系r1 r2 b。
看完了 (-7) % 3下面我们来看一看 7 % (-3) 的情况。根据定义 2计算过程如下图所示
如上图所示可以得到两组结果
商 -2余 1商 -3余 -2
语言语句输出CG 编译cout 7 % (-3);1Java1.6System.out.println(7 % (-3));1Python 2.67 % (-3)-2百度计算器7 mod (-3)-2Google 计算器7 mod (-3)-2
从中我们看到几个很有意思的现象 Java 紧随 C 的步伐而 Python、Google、百度步调一致。难道真是物以类聚联想一下Google 一直支持 PythonPython 也颇有 Web 特色的感觉而且 Google Application Engine 也用的 Python国内的搜索引擎也不约而同地按照 Google 的定义进行运算。 可以推断C 和 Java 通常会尽量让商更大一些。比如在 (-7) mod 3中他们以 -2 为商余数为 -1。在 Python 和 Google 计算器中尽量让商更小所以以 -3 为商。在 7 mod (-3) 中效果相同C 选择了 3 作为商Python 选择了 2 作为商。但是在正整数运算中所有语言和计算器都遵循了尽量让商小的原则因此 7 mod 3 结果为 1 不存在争议不会有人说它的余数是 -2。
上述的认知其实是错误的纠正如下 Java 和 C 的 % 是求余运算符求余遵循让商向 0 靠近的原则即商向 0 方向舍入取整也就是说求余是取 q 更趋近 0 时的 r所以 Java 和 C 计算 7 % (-3) 的结果是 1因为商 -2 更靠近 0而 Python 的 % 是取模运算符取模遵循让商向负无穷靠近的原则商向无穷小方向舍入取整向负无穷方向舍入取整也就是说取模是取 q 更趋近无穷小负无穷时的 r所以 Python、百度、谷歌输出的结果是 -2因为 -3 更靠近负无穷的方向。
如果按照第二点的推断我测试一下 (-7) % (-3)结果应该是前一组语言CJava返回 2后一组返回 -1。请注意这只是假设
于是我做了实际测试
语言语句输出CG 编译cout -7 % (-3);-1Java1.6System.out.println(-7 % (-3));-1Python 2.6-7 % (-3)-1百度计算器-7 mod (-3)-1Google 计算器-7 mod (-3)-1
结果让人大跌眼镜所有语言和计算机返回结果完全一致。
这个眼镜也白跌了上述结果完全符合求余时商向 0 靠近的原则取模时商向负无穷方向靠近的原则所以都输出 -1 根本就在预料之内。
我们看下 (-7) % (-3) 的运算过程如下图所示 所以根据求余时商向 0 靠近的原则取模时商向负无穷方向靠近的原则求余和取模的商都选择 2所以余数和模数都是 -1结果输出的都是 -1。
总结
我们由此可以总结出下面两个结论
对于任何同号的两个整数其取余结果没有争议所有语言的运算原则都是使商尽可能小。对于异号的两个整数C/Java语言的原则是使商尽可能大很多新型语言和网页计算器的原则是使商尽可能小。
这个总结也是错误的。
最后总结除法运算遵循定义 2的规则求余是取 q 更趋近 0 时的 r取模是取 q 更趋近负无穷的 r如果被除数和除数符号相同因为取相同的商值所以余数和模数相同被除数和除数的符号不同则余数和模数会不同。