当 C 有/
运算符将两个数字相除时,具有div()
库函数的目的是什么?
/
有没有不能用但能用的场景div()
?
来自 C99 基本原理文档:
(7.20.6.2 div、ldiv 和 lldiv 函数)因为 C89 在涉及负操作数时具有实现定义的有符号整数除法语义,所以发明了 div 和 ldiv 以及 C99 中的 lldiv,以便为有符号整数提供明确指定的语义整数除法和余数运算。语义被采用与 Fortran 中的相同。由于这些函数同时返回商和余数,因此它们还可以作为一种有效建模底层硬件的便捷方法,将计算这两个结果作为同一操作的一部分。[...] 现在 C99 要求除法运算符具有类似的语义,新程序使用 div、ldiv 或 lldiv 的主要原因是同时获得商和余数。
引自C 编程:现代方法,第 2 版,第 26 章,问答部分。
问:为什么存在 div 和 ldiv 函数?我们不能只使用 / 和 % 运算符吗?
A:
div
and 和 and不太ldiv
一样。回想一下第 4.1 节,在 C89 中将和应用于负操作数不会给出可 移植的结果。如果or是负数, 的值 是向上还是向下舍入是实现定义的,就像 的符号一样 。另一方面, 由and计算的答案不依赖于 implementation。商向零舍入;余数根据公式计算,其中是原数,是商,是除数,/
%
/
%
i
j
i / j
i % j
div
ldiv
n = q x d + r
n
q
d
r
是余数。这里有一些例子:n | d | q | r --------|--------|--------|-------- 7 | 3 | 2 | 1 -7 | 3 | -2 | -1 7 | -3 | -2 | 1 -7 | -3 | 2 | -1
在 C99 中,
/
and%
运算符保证div
产生与and相同的结果ldiv
。效率是存在的另一个
div
原因ldiv
。许多机器都有一个可以计算商和余数的指令,因此调用div
orldiv
可能比单独使用and运算符更快。/
%
div_t
是一个结构,它包含一个商成员和一个余数成员。例如 :
typedef struct {
int quot;
int rem;
} div_t;
div
函数使用/
和操作符的一些简单实现%
。你也可以看到这个话题。
div()
返回result
除法的和remainder
。因此,您不必使用%
运算符来查找remainder
.
正如其他人所提到的,div()
会给你商和余数。这是因为大多数 C 运行时使用的(软件)整数除法算法同时计算两者。
如果目标计算机没有硬件分隔器,则/
操作员通常会被调用,div()
而其余的则被丢弃。运算符也会发生同样的事情,%
只是它是被抛出的商。所以如果你正在做这样的事情:
quot = a / b;
rem = a % b;
您调用了两次除法例程(如果您的计算机不在硬件中执行,除法会非常慢)。所以使用
div()
两者都更快。
(当然,它的可读性也较差,您是否真正获得任何性能优势取决于您的特定平台和编译器。只有div()
在确定它是性能瓶颈时才应该切换到它。记住 Knuth 所说的过早优化。)
太慢了,却又是多余的。 至少 glibc 文档说明了使用 gcc 的情况。我尝试 div 重新实现现有的 itoa() 函数(整数到 ascii),期望 gcc 有内置实现这样一个微不足道的事情,但 gcc 没有它。
char *p = buf;
div_t d = {.quot = n};
while (1)
d = div (d.quot, 10) ,
*p++ = '0' + d.rem ;
上面的代码比使用单独的运算符慢 5..7 倍:
char *p = buf;
while (1)
*p++ = '0' + n % 10,
n /= 10;