`
chinakite
  • 浏览: 124516 次
  • 性别: Icon_minigender_1
社区版块
存档分类
最新评论

取余,真的那么简单吗?

阅读更多
取余的概述
取余 是一个比较常见的运算,在各种编程语言中均有相应的运算符(Java/C的%, Pascal/Delphi的mod等等),我们使用的也比较多,比如
5 % 3 = 2,
10 % 2 = 0.


问题的产生
这样一个问题: -3 % 2 = ? 我们可以使用这样一段Java程序来验证:
System.out.println("result:" + (-3)%2);

运行,结果是:
result:-1

不过问题就在这:记得按照以前的数学书中的叙述,似乎不是这样的,于是将书翻了出来,在 Concrete Mathematics 的82页,看到:

也就是说,x mod y等于 x 减去 y 乘上 x与y的商的下界。于是,上面的-3 mod 2就变成了

奇怪的事情发生了。这个结果与上面程序计算得出的结果不一致。同样,我们使用Mathematics画出图像,来考察-5~5对2取余的情况:

在该图中,同样可以看出,-3对2取余的结果是1,而不是程序计算出来的-1。为何会有这样的结果呢?

程序计算结果原因分析
使用以下一段Delphi程序来考察:
var
   i,j,k:Integer;
begin
   i:=-3;
   j:=2;
   k:=i mod j;
   ShowMessage(IntToStr(k));
end;

编译后,查看汇编,关键的计算部分如下:
Unit1.pas.30: i:=-3;
00486D84 B9FDFFFFFF       mov ecx,$fffffffd
Unit1.pas.31: j:=2;
00486D89 BB02000000       mov ebx,$00000002
Unit1.pas.32: k:=i mod j;
00486D8E 8BC1             mov eax,ecx
00486D90 99               cdq 
00486D91 F7FB             idiv ebx
00486D93 8BDA             mov ebx,edx

在上面的代码中,首先将-3赋值给eax(ecx为临时中间变量),然后将2赋值给ebx,之后执行一条idiv指令。执行该指令后,商在eax中,余数在edx中。这样,与书上结论不一样的原因就出来了:按照书上的定义,应该首先做除法,得到浮点数,然后取其下界。如果附点数是正的,其下界相当与取整;如果浮点数是负的,相当于将小数部分抹去再减一,而idiv指令根本没有计算浮点并取下界的过程,所以造成与数学中的mod定义不一致。实际上,严格的说,我们在程序中使用的余数,其定义为:
x - y(x div y)

这就是二者的区别。这个区别,对于正数,二者计算出的结果是相等的,但是负数就不相等了。这就意味着,如果以后在使用数学中余数相关定理的时候,要注意计算机中余数的计算和数学定义不是完全一致的,所以在计算机上,对于负数,数学定理并不完全适用。当然,对于正数,二者是没有区别的。至于为什么计算机上要这么实现,我想恐怕还是历史原因,最早的计算机如果这样计算除法(取余是靠除法来完成的),那么就涉及到浮点数的计算以及取下界,这样,将比较大的降低效率,所以实现成了这样的方式,一直沿用至今。
分享到:
评论
1 楼 cddcdd 2007-08-28  
按照我这个晚上的研究
你所说的在数学上的定义
这个[x/y]在java中应该对应的是Math.floor(x/y);
而实际在JAVA的运算中,两个整型运算数做x/y操作,输出的出他们的整型商
而两个运算数中其中一个是浮点数,就会输出浮点数的商

所以在Java中做取余操作,x - y(x div y) 
可以x div y 可以解释为 (int)(x/y)

相关推荐

    C++中的取整操作和取余操作,更简单

    在C++编程语言中,取整和取余是两种常见的数学运算,它们在处理数值时起着关键作用。本文将详细介绍这两种操作,并提供相应的代码示例。 首先,我们来看取整操作。C++提供了多种方法来进行取整: 1. 直接赋值给...

    Java别说取余(%)运算简单你真的会吗

    然而,看似简单的取余运算在处理不同符号的数字时,可能会产生一些非直观的结果。这篇文章将深入探讨Java中取余运算的规则,并通过具体的例子来帮助理解。 首先,当两个正数相除时,如 `3%2`,结果是正数,即 `3` ...

    python实现取余操作的简单实例

    在Python编程语言中,取余操作是通过使用求模运算符 `%` 来完成的。这个运算符可以用于两个数值之间,返回它们相除后的余数。例如,如果你有两个数,10和3,当你执行 `10 % 3` 时,结果将是1,因为10除以3的余数是1...

    C#实现带有加、减、乘、除和取余操作计算器源码

    本文将深入探讨如何使用C#语言实现一个基础的计算器程序,包含加、减、乘、除以及取余这五种基本运算。 首先,我们需要创建一个新的C#项目。在Visual Studio或其他C#开发环境中,选择"新建项目",然后选择"控制台...

    MFC简易计算器,可以实现加减乘除,小数点,取余

    在本文中,我们将深入探讨如何使用Microsoft Foundation Class (MFC) 库来开发一个简易计算器,这个计算器能够执行基本的数学运算,包括加法、减法、乘法、除法,以及更高级的功能如小数点操作、取余、正切、正弦和...

    PHP实现大数(浮点数)取余的方法

    首先,我们通常提到的取余运算,最简单的表示就是用“%”符号。例如,对于整数5除以2,可以写成“5 % 2”,得到的余数为1。但如果除数是一个大数,比如***除以1000,那么使用“%”符号就不适用了,因为这样的数值...

    PHP简易计算器,有+-×÷取余功能,包含各种错误检查

    本项目是一个基于PHP语言开发的简易计算器程序,具备基本的算术运算能力(加、减、乘、除、取余),并实现了较为完善的输入验证和错误处理机制。通过该程序用户可以输入两个数值,并选择相应的运算符来完成计算操作...

    js代码-翻转整数(循环取余)

    以下是一个简单的JavaScript实现示例: ```javascript function reverseInteger(x) { let reverseNum = 0; let isNegative = x ; x = Math.abs(x); while (x > 0) { let digit = x % 10; // 取最后一位 ...

    基于Python编写一个计算器程序,实现简单的加减乘除和取余二元运算

    在Python编程中,创建一个简单的计算器程序可以轻松地实现基本的加减乘除以及取余数的二元运算。下面我们将详细讨论如何使用Python来编写这样的计算器。 首先,Python语言以其简洁明了的语法和丰富的内置功能使得...

    PHP中余数、取余的妙用

    如果索引是奇数(`$key % 2 == 1`),那么就输出`<li>`开始标签;如果索引是偶数(`$key % 2 == 0`),则输出`</li>`结束标签。这样,每隔一个元素,列表项就会自动关闭,形成一个有效的HTML结构。 另一个例子展示...

    基于Python编写一个计算器程序,实现简单的加减乘除和取余二元运算

    结合lambda表达式、函数调用运算符、标准库函数对象、C++11标准新增的标准库function类型,编写一个简单的计算器,可实现简单的加、减、乘、除、取余二元运算。代码如下: #include "pch.h" #include #include #...

    c++简单除法和取余数3-2!

    与我的文章配套 输入两个整数,输出商和余数

    矩阵键盘简易计算器(Keil+proteus仿真).rar

    通过输入数字和运算符号进行简单计算,按下等于键将计 算的值输出到数码管显示(最大显示8位),计算结果超过8位则输出符号“-”。清屏键用于结束此次运算并清除数码管显示。(计算值-32768~32767)

    微信小程序-一个简单的微信小程序-简易计算器

    支持简单的加减乘除和取余数 支持连续操作, 比如做了加法以后, 结果会直接作为第一个操作数进入下一轮操作 支持删除单个数字和一次性全部清空LICENSE Copyright 2016 boyce.ywr@gmail.com Permission is hereby ...

    编译原理三级项目pl0扩展

    原始的PL0仅支持简单的赋值操作,如`a = b`。在扩展后,我们引入了乘法赋值`a *= b`和除法赋值`a /= b`,这允许程序员更简洁地进行数学计算。 3. 取反和取余操作: 扩展版的PL0新增了逻辑非操作符(`!`)和取余...

    Optical simulation with OSLO 交大光電陳志隆教授

    在课程的另一部分,陈教授介绍了几何光学的高级概念,包括使用简单凸透镜和Wollaston双凹透镜进行的实验。这些实验不仅回顾了历史上的光学事件,也展示了孔径光阑(Aperture stop)的位置对于光学系统性能的影响。...

    android计算器

    5. **数据存储**:虽然这个计算器没有明确提及数据存储,但在实际应用中,如果需要保存历史记录或者用户的设置,可以利用SharedPreferences来存储简单的键值对,或者使用SQLite数据库来存储更复杂的数据结构。...

    编译原理-作业-简单c++计算器

    在本项目中,我们探讨的是一个基于编译原理的简单C++计算器程序。这个作业旨在帮助学生理解如何将高级语言的语句转化为机器可执行的指令。编译器是实现这一转换的关键工具,它的工作原理涉及到词法分析、语法分析、...

    MFC做的一个简单计算器

    【MFC制作简单计算器】 MFC(Microsoft Foundation Classes)是微软提供的一套C++类库,用于构建Windows应用程序。这个项目“MFC做的一个简单计算器”显然是使用MFC框架开发的一个基础计算工具,旨在帮助用户执行...

Global site tag (gtag.js) - Google Analytics