C++取余和取模运算实例

13 / 5 = 2
13 % 5 = 3
int(12.5) = 12
ceil(12.5) = 13
floor(12.5) = 12
【%】取余,【/】取模
【ceil()】向上取整,【floor】向下取整

#include <iostream>
#include <math.h>

int main()
{
	std::cout << "13 / 5 = " << 13 / 5 << "\n";
	std::cout << "13 % 5 = " << 13 % 5 << "\n";

	std::cout << "int(12.5) = " << int(12.5) << "\n";

	// 向上取整double ceil(double x) 
	std::cout << "ceil(12.5) = " << ceil(12.5) << "\n";
	// 向下取整double floor(double x) 
	std::cout << "floor(12.5) = " << floor(12.5) << "\n";
	/**************************************
		也可以用数据类型强制转换,那要看数据的大小
		可以用int()或long()
		比如int(104.23) = 104
	***************************************/
}
/*******************输出****************** 
	13 / 5 = 2
	13 % 5 = 3
	int(12.5) = 12
	ceil(12.5) = 13
	floor(12.5) = 12
******************************************/

/*
	"%"为取余号,不用多说。   
	"/"号现在整形运算是取整,浮点运算时为除法运算,
	如54/10结果为5,54.0/10.0结果为5.4
	而且取整时不进行四舍五入只取整数部分,如54/10和56/10是5.   

	ceil()取整数的较大数,相当于不管余数是什么都会进一位。
	如ceil(54.0/10.0)结果为6.   

	floor()取整数的较小数,相当于"/"号,即不管余数部分是什么都不进行进位。
	如floor(56.0/10.0)的结果是5.
*/
取模和取余的区别

其实取模和取余在目标上是一致的,但是因为语言对取余和取模上定义的不同,导致得到的结果不同。

对取余和取模定义不同的语言中,两者的不同点只有一个

  • 取余运算在计算商值向0方向舍弃小数位
  • 取模运算在计算商值向负无穷方向舍弃小数位


同时,也可以这样理解:

  • 取余,遵循尽可能让商大的原则
  • 取模,遵循尽可能让商小的原则


从上面的区别可以总结出,取余(rem)和取模(mod)在被除数、除数同号时,结果是等同的,异号时会有区别,所以要特别注意异号的情况。

下面来看一些例子
取模

5 mod 3 = 2
-5 mod 3 = 1
5 mod -3 = -1
-5 mod -3 = -2

取余

5 rem 3 = 2
-5 rem 3 = -2
5 rem -3 = 2
-5 rem -3 = -2

经过测试,在C/C++, C#, JAVA, PHP这几门主流语言中,’%’运算符都是做取余运算,而在python中的’%’是做取模运算。

此外,余数在数学中的定义是始终大于等于0的,而对于某些编程语言的取余运算不是按照上面的定义来执行的,因此才会出现余数小于0的情况。

说了这么多,我们在使用取模(取余)运算时要注意的地方有一个,当除数和被除数出现异号的情况时,程序移植的时候要特别小心,因为不同语言对取模和取余的定义可能是不同的。

数学与编程——求余、取模运算及其性质

一、求余运算(Remainder)

(参考维基百科: http://zh.wikipedia.org/wiki/余数  http://en.wikipedia.org/wiki/Remainder http://en.wikipedia.org/wiki/Euclidean_division http://zh.wikipedia.org/wiki/同余)

Euclidean division:Given two integers a and b, with b ≠ 0, there exist unique integers q and r such that a = bq + r and 0 ≤ r < |b|, where |b| denotes the absolute value of b.

(术语:  a 被除数 dividend ; b 除数 divisor;q 商 quotient;r 余数 remainder)

按照上面的定义:余数唯一并始终大于或等于0,并可以拓展到两个整数为正数或负数的情况。

但是,程序设计语言求余算法并不是按照上面的定义来执行。

我们引出另一种余数定义:a = bq + r and 0 <= |r| < |b| 。于是,我们可以发现这种情况下余数可能不止一个。

例子:a = 43 b = 5时:

43 = 5 * 8 + 3 : q = 8;r = 3 (r > 0)

43 = 5 * 9 –  2 : q = 9;r = -2 (r < 0)

当a 和 b 含有负数时也存在这两种余数。

例子:a = 43 b = -5时:

43 = -5 * -8 + 3 : q = -8;r = 3 (r > 0)

43 = -5 * -9 –  2 : q = -9;r = -2 (r < 0) 

大多数程序设计语言要求余数与被除数的正负号相同(参考自《C陷阱与缺陷》,强调了程序的可移植性问题,即被除数或除数含有负数时要谨慎对待)。这说明不同程序设计语言实现时对上述例子求余时可能是上面不同的解。

二、取模运算 (Modulo)

(参考维基百科:http://en.wikipedia.org/wiki/Modulo_operation  http://en.wikipedia.org/wiki/Modular_arithmetic)

In computing, the modulo operation finds the remainder after division of one number by another (sometimes called modulus).

上面这句话说明,取模运算和求余运算的目标都是一致的。只是不同程序设计语言时实现的方式可能不同,也就是上面所说的采用另一种余数定义时,含有两种余数结果。一些语言可能会采取第一个结果;另一些语言可能会采取第二个结果;还有些语言可能会把取模和求余分开定义,分别采取两种结果。维基百科里面就列出了一些程序设计语言采取的操作,常见的为以下几种:

1.求余结果或取模结果的正负号与被除数相同;

2.求余结果或取模结果的正负号与除数相同;

3.求余结果或取模结果的总是正数;

4.求余结果或取模结果由实现定义;

5.求余结果或取模结果为最接近0的数;

求余运算和取模运算小结:有人会把取模运算和求余运算分开解释,又采用特定的语言去举例,我认为这两种运算目标都是一致,只是求余运算倾向于数学,而取模运算倾向于计算机科学,之所以不同语言会有不同的结果,本质是因为根据求余运算定义导致余数不唯一时不同程序设计语言采用了不同的结果,但他们都会根据某种依据来给出唯一的结果。这也告诉我们,程序移植时必须当心这种差别,特别是当两个整数含有负数的情况。

三、取模运算性质

术语:

For a positive integer n, two integers a and b are said to be congruent modulo n, and written as

一些有用的性质(可证明):

如果a≡b(mod m),x≡y(mod m),则a+x≡b+y(mod m)。

如果a≡b(mod m),x≡y(mod m),则ax≡by(mod m)。

如果ac≡bc(mod m),且c和m互质,则a≡b(mod m) (就是说同余式两边可以同时除以一个和模数互质的数)。

作者:

喜欢围棋和编程。

 
发布于 分类 编程标签

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注