整数除法的行为是啥?
Posted
技术标签:
【中文标题】整数除法的行为是啥?【英文标题】:What is the behavior of integer division?整数除法的行为是什么? 【发布时间】:2011-04-05 21:27:06 【问题描述】:例如,
int result;
result = 125/100;
或
result = 43/100;
结果总是分区的底数吗?定义的行为是什么?
【问题讨论】:
总结:有符号整数除法向零截断。对于非负结果,这与 floor 相同(向 -Infinity 舍入)。 (请注意,C89 不保证这一点,请参阅答案。) 每个人都一直在说“向零截断”或“天花板”或“地板”,就像代码在深思熟虑地决定使用哪种技术一样。如果代码可以说话,它会说"I just throw the dam fraction part in the trash and move on with life"
@TimothyL.J.Stewart “代码”正在做出深思熟虑的决定。根据规范,整数除法是 T(runcation)-除法。因此,模/余数运算符的实现方式与使用另一种语言(例如 Python 或 Ruby)不同。请参阅 this 了解语言执行模运算符的不同方式列表和 this 论文,其中列出了编程语言决定执行 div/modulo 的至少五种常见方式。
@13steinj 我说的是根据 cmets 口语化的说法,它正在变成“它正在向零截断......不,它是地板......不,如果它是负数,它的天花板......”有时技术性确实如此不要像我们希望的那样用人类记忆传播到未来,而是直观地知道“分数部分被扔掉”你可以得出技术点。技术是一个沉重的负担,但直觉是轻而易举的,就像风一样,我会带着那些远方和广泛的,必要时我会知道从哪里开始。就像你链接的那篇论文一样,谢谢。
我回答here 强调欧几里得除法(整数除法和模运算符之间的相互作用)。
【参考方案1】:
结果总是分区的底数吗?定义的行为是什么?
不完全是。它朝 0 舍入,而不是取整。
6.5.5 乘法运算符
6 整数相除时,/操作符的结果是任意一个的代数商 小数部分被丢弃。88) 如果商 a/b 是可表示的,则表达式 (a/b)*b + a%b 应该等于 a。
以及相应的脚注:
这通常称为“向零截断”。
当然要注意两点:
3对操作数执行通常的算术转换。
和:
5 / 运算符的结果是 商从除法 第二个操作数的第一个操作数;这 % 运算符的结果是 余。 在这两种操作中,如果 第二个操作数的值为零, 行为未定义。
[注:强调我的]
【讨论】:
...当然,除非您将一个负数除以一个正数(或 v.v.),在这种情况下它将是天花板。 既不是地板也不是天花板,是小数部分的截断,概念不同! @Will A:不。它被定义为向零截断。将其称为其他任何东西只会增加混乱,因此请不要这样做。 至少从数学角度来看,向零截断等价于“如果 > 0 则下限否则上限”。我认为仅仅称它为截断比称它为地板/天花板更简单,但两者都是有效的。无论如何,Will A 的观点是正确的:Dirkgently 的回答部分不正确,因为他说 OP 关于结果是除法的底线是正确的。 @Philip Potter:我不认为它是在 C89 中定义的,也不是在 1998 年的 C++ 标准中。其中,当然(a / b) * b + a % b == a
必须满足,a % b
的绝对值必须小于a
,但是对于负a
或b
,a % b
是负数还是未指定。 【参考方案2】:
Dirkgently 在 C99 中给出了整数除法的an excellent description,但您还应该知道,在 C89 中,带有负操作数的整数除法具有实现定义的方向。
来自 ANSI C 草案 (3.3.5):
如果任一操作数为负数,则 / 运算符的结果是小于代数商的最大整数还是大于代数商的最小整数是实现定义的,% 运算符的结果的符号也是如此.如果商 a/b 是可表示的,则表达式 (a/b)*b + a%b 应等于 a。
因此,当您遇到 C89 编译器时,请注意负数。
C99 选择向零截断是一个有趣的事实,因为 FORTRAN 就是这样做的。请参阅 comp.std.c 上的 this message。
【讨论】:
而 C99 草案 N1256 前言第 5 段提到reliable integer division
作为新的语言功能。太棒了*-*
.
截断是最常见的 CPU 硬件(例如 x86)的行为方式,因此做出不同的选择会很疯狂。 IDK 首先出现,Fortran 语义或硬件行为,但它们也相同并非巧合。
@PeterCordes:大多数常见的 CPU 硬件可以比截断除法更快地执行大多数常量的下限除法。恕我直言,当expr1
的两个实例以相同的方式组合相同的对象时,标准最好说expr1 / expr2
和expr1 % expr2
必须彼此一致,对于expr2
也是如此,但是截断与下限除法的选择在其他方面未指定。这将允许更有效的代码生成而不会破坏太多兼容性(如果愿意,实现可以记录特定行为)【参考方案3】:
是的,结果总是被截断为零。它将向最小的绝对值四舍五入。
-5 / 2 = -2
5 / 2 = 2
对于无符号和非负符号值,这与 floor 相同(向 -Infinity 舍入)。
【讨论】:
@dan04: 是的 floor 只对正整数有效 :)【参考方案4】:如果结果是负数,C 会向 0 截断而不是取整 - 我从这篇文章中了解到为什么 Python 整数除法总是在这里取整:Why Python's Integer Division Floors
【讨论】:
我同意评论是否让 (neg % pos) 变为负数是否有用?在相关的说明中,我想知道在“unsignedvar > signedvar”的某些情况下所需的算术错误行为是否有用?我可以理解不需要始终正确行为的理由;我认为没有理由要求错误的行为。 +1 很好地参考了为什么地板是整数除法的正确行为(与 C 的定义相反,它被破坏并且几乎没有用处)。 @supercat 考虑:filtered = (k - 1) * filtered + value + carry; carry = filtered % factor; filtered /= factor
,随着value
的值的变化而迭代。它对具有时间常数 k
... 的一阶低通滤波器进行了很好的整数逼近...但只有当除法被截断并且 carry
得到负值时它才是对称的。这两种除法行为都会时不时派上用场。
@hobbs:我不认为上面的代码在信号过零时会表现得很干净。如果div
是一个取整除法运算符并且factor
是奇数,那么filtered += (filter+(factor div 2)) div factor
将为直到INT_MAX-(factor div 2)
的所有值产生干净和对称的行为。
@supercat 它确实有效;该代码只是从我在原子钟控制器中运行了一段时间的代码中略微提炼出来的。【参考方案5】:
结果是否总是分区的底数?
没有。结果会有所不同,但只有负值才会发生变化。
定义的行为是什么?
为了明确地板向负无穷舍入,而整数除法向零舍入(截断)
对于正值,它们是相同的
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
【讨论】:
【参考方案6】:我知道人们已经回答了你的问题,但用外行的话:
5 / 2 = 2
//因为 5 和 2 都是整数,整数除法总是截断小数
5.0 / 2 or 5 / 2.0 or 5.0 /2.0 = 2.5
//这里 5 或 2 或两者都有小数因此你得到的商将是十进制的。
【讨论】:
以上是关于整数除法的行为是啥?的主要内容,如果未能解决你的问题,请参考以下文章