关于整数除法

     整数除法,在我看来,是编程语言中一个既受重视又不是很受重视的问题。说它受重视,是因为我们在谈到除法的时候,总是会提到,当两个整数进行除法操作时,其行为与浮点数乘法是不一样的,小数部分被舍去了;说它不受重视,是因为讲这个问题的时候,整数除法的语义没有一次性地讲清楚,结果碰到一些不常见的问题,就没有一个清晰的逻辑来得到结果。

    就我所知,整数除法的语义是有好几种的,下面分别介绍。有几种定义是以算术上的除法(实数商)为基础的,或者就编程语言来说,是基于浮点数除法的,即就算是两个整数相除,所得的值也是把整数当作浮点数处理然后得到的。这种除法运算得到的商,借用标准C中的术语,我们统称为代数商(algebraic quotient)。对于a,b两个整数,本文中用a div b表示整数除法的商,a/b表示代数商, a mod b表示a除以b后所得余数。

    第一种,floor division。代数商取下整数(某实数的下整数是小于或等于它的最大整数),a div b = floor(a/b)。Python 2.x和Mathematica中都是这个定义。举例:5 div 9 = 0, 5 div -9 = -1, -5 div 9 = -1, -5 div -9 = 0。

    第二种,truncation division(不是正式的名称,我姑且这么说)。这是标准C中的定义,比如C99中的定义是“When integers are divided, the result of the / operator is the algebraic quotient with any fractional  part  discarded”,即直接将代数商中的小数部分丢掉就得到整数除法的商,即整数除法的商等价于浮点数除法的商取整后的结果。C的语言的一些实现,如微软Visual C++(Visual Studio 2010)采用的这种标准,在Visual C++帮助中关于C语言的参考手册中,是这样描述的:

If two integer operands are divided and the result is not an integer, it is truncated according to the following rules:

  • The result of division by 0 is undefined according to the ANSI C standard. The Microsoft C compiler generates an error at compile time or run time. 
  • If both operands are positive or unsigned, the result is truncated toward 0.
  • If either operand is negative, whether the result of the operation is the largest integer less than or equal to the algebraic quotient or is the smallest integer greater than or equal to the algebraic quotient is implementation defined. (See the Microsoft Specific section below.)”。

而所谓“Microsoft Specific section below”是这样的:

Microsoft Specific
     In division where either operand is negative, the direction of truncation is toward 0.
     If either operation is negative in division with the remainder operator, the result has the same sign as the dividend (the first operand in the expression).

END Microsoft Specific”,

而实际上“truncated toward 0”就是标准C中“with any fractional  part  discarded”的一种等价说法,因为前者意味着绝对值的减小(向着0的方向),后者也是同样的意思(丢掉了小数部分)。举例, 5 div 9 =0, 5 div -9 = 0, -5 div 9 = 0, -5 div -9 = 0。

     第三种,数论中的带余除法(或欧几里得除法,欧氏除法算式)。“一般地,设a,b为整数,且b不为0,则存在唯一的一对整数q和r,使得a=bq+r,其中r非负且小于b的绝对值”。根据这个定理可以定义q为整数除法的商,r为整数除法的余数。举例,5 div 9 = 0, 5 div -9 = 0, -5 div 9 = -1, -5 div -9 = 1。


关于余数

      余数的定义是与商的定义紧密相关的,因为一般来说,整数除法的商和余数都满足一个约束,在C99标准中是这么说的,“If  the  quotient a/b is  representable,  the  expression (a/b)*b + a%b shall equal a”,使用本文中的表示即有 (a div b)*b + a mod b = a。带余除法根据定义就自然满足这种约束,在C之外的语言,我看也是满足这种定义的。举例,根据这个约束公式:

     在使用第一种整数除法定义的Python中(Python中用%表示求余数),5 % 9 = 5,5 % -9 = -4, -5 % 9 = 4, -5 % -9 = -5;

     在使用第二种整数除法定义的C语言中(使用Visual C++实现),5 % 9 = 5, 5 % -9 = 5, -5 % 9 = -5, -5 % -9 = -5;

    在第三种定义即带余除法中, 5 mod 9 = 5, 5 mod -9 = 5, -5 mod 9 = 4, -5 mod -9 = 4。

可以看出,在前两种的定义下,余数是可以为负,这与第三种带余除法完全不同。附带补充一点,前两种定义都是程序语言中实际所用的定义,所以在程序中使用%求余数的话可能会产生负数,这样的话,对于整数奇偶性判断,如果用求余的方法,那么最好是判断 i%2 与 0的关系,而不是判断 i%2 与 1的关系,因为 i%2 的结果可能是 -1。当然,判断奇偶性最好还是用位操作,如果语言支持的话。


附1:有以取下整数定义商的,有以取整定义商的,但是以取上整数定义商的好像没有。

附2:C语言中的几种取整方法(转):

  • 1、直接赋值给整数变量。如:int i = 2.5; 或 i = (int) 2.5。这种方法采用的是舍去小数部分。
  • 2、C/C++ 中的整数除法运算符“/”本身就有取整功能(int / int),而下面介绍的取整函数返回值是double。整数除法对正数的取整是舍去小数部分。但是整数除法对负数的取整结果和使用的C编译器有关。
  • 3、使用floor函数。floor(x)返回的是小于或等于x的最大整数。如:floor(2.5) = 2,floor(-2.5) = -3。
  • 4、使用ceil函数。ceil(x)返回的是大于或等于x的最小整数。如:ceil(2.5) = 3,ceil(-2.5) = -2,floor()是向负无穷大舍入,floor(-2.5) = -3;ceil()是向正无穷大舍入,ceil(-2.5) = -2。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值