div函数有用吗(stdlib.h)

Is div function useful (stdlib.h)?

本文关键字:stdlib 函数 有用 div      更新时间:2023-10-16

在C中有一个叫做div的函数,c++ (stdlib.h)

div_t div(int numer, int denom);
typedef struct _div_t
{
  int quot;
  int rem;
} div_t;

但是C、c++有/和%操作符

我的问题是:"当有/和%操作符时,div函数有用吗?"

是的,它在一次运算中计算商和余数。

除此之外,同样的行为可以通过/ + %来实现(并且一个体面的优化器无论如何都会将它们优化成单个div)。

总结一下:如果您关心挤出最后一点性能,这可能是您的选择函数,特别是如果您的平台上的优化器不是那么先进。嵌入式平台通常就是这种情况。

div()函数返回一个结构,其中包含第一个参数(分子)除以第二个参数(分母)的商和余数。有四种变体:

  1. div_t div(int, int)
  2. ldiv_t ldiv(long, long)
  3. lldiv_t lldiv(long long, long long)
  4. 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()的语义不同于%和/的语义,这在某些情况下很重要。这就是为什么下面的代码是在精神病的答案中显示的实现:

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/ba%b代码,这种需求就减少了。


这是div() 的令人信服的原因,它解释了udiv_t udiv(unsigned numer, unsigned denom)在C规范中缺席的原因:a/b使用负操作数的实现依赖结果的问题即使在c99之前的unsigned中也不存在。

可能是因为在许多处理器上,div指令同时产生两个值,并且您总是可以指望编译器能够识别相同输入上相邻的/和%操作符可以合并为一个操作。

如果两个值都需要,则花费的时间更少。在进行除法运算时,CPU总是同时计算余商。如果使用"/"answers"%"一次,cpu将计算两个数字的两倍。

(原谅我英语不好,我不是母语)