div函数有用吗(stdlib.h)?
在C,C ++中有一个名为div的函数(stdlib.h)
div_t div(int numer, int denom); typedef struct _div_t { int quot; int rem; } div_t;
但C,C ++有/和%运算符。
我的问题是:“ 当有/和%运算符时,div函数有用吗?”
div()函数返回一个结构,该结构包含第一个参数(分子)除以第二个(分母)的除数和余数。 有四种变体:
-
div_t div(int, int)
-
ldiv_t ldiv(long, long)
-
lldiv_t lldiv(long long, long long)
-
imaxdiv_t imaxdiv(intmax_t, intmax_t
(intmax_t表示系统上可用的最大整数类型)
div_t
结构如下所示:
typedef struct { int quot; /* Quotient. */ int rem; /* Remainder. */ } div_t;
实现只是使用/
和%
运算符,因此它不是一个非常复杂或必要的函数,但它是C标准的一部分(由[ISO 9899:201x] [1]定义)。
请参阅GNU libc中的实现:
/* Return the `div_t' representation of NUMER over DENOM. */ div_t div (numer, denom) int numer, denom; { div_t result; result.quot = numer / denom; result.rem = numer % denom; /* The ANSI standard says that |QUOT| <= |NUMER / DENOM|, where NUMER / DENOM is to be computed in infinite precision. In other words, we should always truncate the quotient towards zero, never -infinity. Machine division and remainer may work either way when one or both of NUMER or DENOM is negative. If only one is negative and QUOT has been truncated towards -infinity, REM will have the same sign as DENOM and the opposite sign of NUMER; if both are negative and QUOT has been truncated towards -infinity, REM will be positive (will have the opposite sign of NUMER). These are considered `wrong'. If both are NUM and DENOM are positive, RESULT will always be positive. This all boils down to: if NUMER >= 0, but REM < 0, we got the wrong answer. In that case, to get the right answer, add 1 to QUOT and subtract DENOM from REM. */ if (numer >= 0 && result.rem < 0) { ++result.quot; result.rem -= denom; } return result; }
是的,它是:它在一次操作中计算商和余数。
除此之外,使用/
+ %
可以实现相同的行为(并且一个体面的优化器无论如何都会将它们优化为单个div
)。
总结一下:如果你关心挤出最后一点性能,这可能是你选择的function,特别是如果平台上的优化器不是那么先进。 嵌入式平台通常就是这种情况。 否则,请使用您认为更具可读性的任何方式。
div()的语义不同于%和/的语义,这在某些情况下很重要。 这就是为什么以下代码在psYchotic的答案中显示的实现:
if (numer >= 0 && result.rem < 0) { ++result.quot; result.rem -= denom; }
%可能会返回否定答案,而div()始终返回非负余数。
检查WikiPedia条目 ,特别是“div总是向0舍入,与C中的普通整数除法不同,其中负数的舍入取决于实现。”
div()
满足了C99之前的需求:可移植性
在C99之前 ,带有负操作数的a / b
商的舍入方向取决于实现。 使用div()
,舍入方向不是可选的,而是指定为0. div()
提供统一的便携式除法。 次要用途是在计算商和余数时所需的代码的潜在效率。
使用C99及更高版本, div()
和/
指定相同的圆形方向,并且使用更好的编译器优化附近的a/b
和a%b
代码,需求减少了。
这是div()
的令人信服的理由,它解释了在C规范中缺少udiv_t udiv(unsigned numer, unsigned denom)
:带有负操作数的a/b
的实现依赖结果的问题对于unsigned
是不存在的,即使在预C99。
如果您需要两个值,则花费的时间更少。 执行除法时,CPU始终计算余数和商。 如果使用“/”一次和“%”一次,cpu将计算两次数。
(原谅我可怜的英语,我不是本地人)
可能是因为在许多处理器上,div指令产生两个值,并且您始终可以依赖编译器来识别相同输入上的相邻/和%运算符可以合并为一个操作。