整数除法的行为是什么?


209

例如,

int result;

result = 125/100;

要么

result = 43/100;

结果将永远是部门的底线吗?定义的行为是什么?


5
摘要:有符号整数除法将截断为零。对于非负结果,此值与下限相同(朝-Infinity取整)。(请注意,C89不能保证这一点,请参见答案。)
彼得·科德斯

5
每个人都在说“截断为零”,“上限”或“下限”,就像代码正在仔细决定使用哪种技术一样。如果代码可以说话,它会说"I just throw the dam fraction part in the trash and move on with life"
Timothy LJ Stewart

3
@ TimothyL.J.Stewart“代码”正在刻意做出决定。根据规范,整数除法是指T(runcation)-除法。因此,与其他语言(例如Python或Ruby)相比,模/余数运算符的使用方式有所不同。见对不同的方式做语言模运算符列表以及文件,其中列出了至少五种常见方式编程语言决定做DIV /模数。
13steinj

1
@ 13steinj我的评论是用口语表达的,它变成了“向零截断……不等于下限……不等于负数上限……”有时技术不会随着人类的记忆传播到未来就像我们希望的那样,但是凭直觉知道“小部分被扔掉”,您可以得出技术要点。技术性是沉重的负担,但直觉却随风而来,让人耳目一新,我将带走这些东西,并且在必要时我会知道从哪里开始。就像您链接的那篇论文一样,谢谢。
蒂莫西LJ斯图尔特

在这里回答 的重点是欧几里得除法(整数除法和模运算符之间的相互作用)。
Picaud Vincent

Answers:


182

结果将永远是部门的底线吗?定义的行为是什么?

是的,两个操作数的整数商。

6.5.5乘法运算符

6当整数分割,/运算的结果是代数商与丢弃任何小数部分。88)如果商a / b是可表示的,则表达式(a / b)* b + a%b等于a。

以及相应的脚注:

88)这通常被称为“向零截断”。

当然要注意两点:

3在操作数上执行常规的算术转换。

和:

5 /运算符的结果是第一个操作数除以第二个的商。%运算符的结果是余数。在这两个操作中,如果第二个操作数的值为零,则行为是不确定的。

[注意:重点是我的]


26
...当然,除非您将负数除以正数(或vv),在这种情况下将是上限。
将在

74
它既不是地板也不是天花板,它是小数部分的截断,在概念上是不同的!
lornova

38
@Will A:否。它被定义为向零截断。调用其他任何东西只会增加混乱,因此请不要这样做。
马丁·约克

44
至少从数学角度来看,截断为零等效于“如果> 0,则将其他上限降低”。我认为,仅将其称为截断比将其称为落地/天花板更简单,但是任何一种都是有效的。无论如何,威尔A的观点是正确的:Dirkgently的答案在某种程度上是不正确的,因为他表示OP对结果是部门底线是正确的。
Brian

9
@Philip Potter:我认为它不是在C89中定义的,也不是在1998 C ++标准中。在这些,当然(a / b) * b + a % b == a必须满足,绝对值a % b必须是小于a,但无论a % b是为负负ab没有指定。
David Thornley,2010年

39

Dirkgently 很好地描述了C99中的整数除法,但是您也应该知道,在C89中,带有负操作数的整数除法具有实现定义的方向。

从ANSI C草案(3.3.5):

如果任一操作数为负,则/运算符的结果是小于代数商的最大整数,还是大于代数商的最小整数,这是实现定义的,%运算符的结果也是如此。如果商a / b是可表示的,则表达式(a / b)* b + a%b等于a。

因此,当您使用C89编译器时,请当心负数。

一个有趣的事实是,C99选择了将截断取零,因为FORTRAN就是这样做的。请参阅comp.std.c上的此消息


2
C99草案N1256前言第5段提到reliable integer division了新的语言功能。惊人*-*
西罗Santilli郝海东冠状病六四事件法轮功

截断是最常见的CPU硬件(例如x86)的行为方式,因此做出不同的选择会很疯狂。首先出现的IDK是Fortran语义或硬件性能,但是它们相同也不是巧合。
彼得·科德斯

2
@PeterCordes:大多数常见的CPU硬件可以用大多数常量进行底除运算,而快于截断除法运算。恕我直言,当两个实例的实例以相同的方式组合相同的对象时,最好让标准这样说,expr1 / expr2并且expr1 % expr2必须彼此一致,expr1对于expr2,同样如此,但是对于截断和底数分割的选择则未指定。那将允许更高效的代码生成而不会破坏太多的兼容性(并且实现可能倾斜地记录特定行为)
supercat

23

在结果为负数的情况下,C会截断为0而不是下限-我了解到以下内容,为什么Python整数除法总是在此处下限:为什么Python的整数除法


3
我同意这样的评论,怀疑(负pos)变负是否有用?在相关说明中,我想知道在“ unsignedvar> signedvar”的某些情况下所需的算术错误行为是否有用吗?我可以理解不要求总是正确行为的理由;我认为没有要求犯错误行为的理由。
supercat

8
+1可以很好地说明为什么地板是整数除法的正确行为(与C的定义相反,C的定义是无效的,几乎不再有用)。
R .. GitHub停止帮助ICE,2010年

@supercat考虑:filtered = (k - 1) * filtered + value + carry; carry = filtered % factor; filtered /= factor,通过更改的值进行迭代value。它可以很好地逼近具有时间常数的一阶低通滤波器的整数,k但是如果除法被截断并carry得到负值,则它只是对称的。这两种划分行为有时会派上用场。
hobbs

1
@hobbs:我认为当信号过零时,上面的代码不会表现得很干净。如果div是底数除法运算符且factor为奇数,则filtered += (filter+(factor div 2)) div factor对于直到的所有值都将产生干净且对称的行为INT_MAX-(factor div 2)
超级猫

@supercat它确实可以工作;该代码只是从我已经在原子钟控制器中运行了一段时间的内容中稍微提取出来的。
hobbs

21

是的,结果总是被截断为零。它将舍入到最小的绝对值。

-5 / 2 = -2
 5 / 2 =  2

对于无符号和非负符号值,此值与下限相同(四舍五入为-Infinity)。


43
截断,而不是地板。
2010年

9
@ dan04:yep floor仅对正整数有效:)
Leonid

13

结果将永远是部门的底线吗?

不会。结果会有所不同,但仅对负值会发生变化。

定义的行为是什么?

为了使底数舍入为负无穷大,而整数除法则舍入为零(截断)

对于正值,它们是相同的

int integerDivisionResultPositive= 125/100;//= 1
double flooringResultPositive= floor(125.0/100.0);//=1.0

对于负值,这是不同的

int integerDivisionResultNegative= -125/100;//=-1
double flooringResultNegative= floor(-125.0/100.0);//=-2.0

0

我知道人们已经回答了您的问题,但是用外行的话来说:

5 / 2 = 2 //因为5和2都是整数,并且整数除法总是截断小数

5.0 / 2 or 5 / 2.0 or 5.0 /2.0 = 2.5 //此处5或2或两者都具有小数,因此您将得到的商将为小数。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.