【问题标题】:Is div function useful (stdlib.h)? [duplicate]div 函数有用吗(stdlib.h)? [复制]
【发布时间】:2011-07-16 15:06:26
【问题描述】:

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函数有用吗?”

【问题讨论】:

  • 已经在this question回答了
  • What is purpose of the div() library function? 的可能重复项(非特拉法马多尔人注意:线性时间并不重要。这个问题比这个问题得到了一些更好、更现代的答案。)
  • 它的答案过度关注一个在 20 年前的 C99 中不再重要的细节......

标签: c++ c integer-division


【解决方案1】:

是的,它是:它计算 one 操作中的商和余数。

除此之外,/+% 也可以实现相同的行为(无论如何,一个体面的优化器会将它们优化为单个 div)。

总结一下:如果您关心挤出最后一点性能,这可能是您选择的功能,特别是如果您平台上的优化器不是那么先进。这通常是嵌入式平台的情况。否则,请使用您认为更具可读性的任何方式。

【讨论】:

  • 一个不错的优化器会用两个乘法、一个位移位和一个减法(在大多数情况下)替换/%
  • @Vlad:你的意思是在一个操作中计算商和余数是如此重要,以至于定义了一个新函数?
  • 历史上是这样;长期以来,除法在 CPU 上是一项非常昂贵的操作,因此欢迎编译器提供任何帮助。现在,这没什么大不了的,但没有理由从 C 中删除 div(),所以它仍然存在。
  • 只有当分母为常数时,乘法技巧才有效。
  • @Vlad:那部分不是建议用乘法代替除法(用常数)吗? (无论如何,128 位除法非常罕见)
【解决方案2】:

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;
}

【讨论】:

  • @Jørgen:无论如何,源代码是实现定义的 :-)
  • 弗拉德:请参阅我的答案以获得澄清。
  • 对于除法和余数的 C11(和 C99?)规范,兼容的编译器甚至会有 numer &gt;= 0 &amp;&amp; result.rem &lt; 0 吗?
  • 很好的答案。只是表明,如果标准库有一个似乎不必要的函数,那么很有可能有人有充分的理由编写它。
  • 要更清楚。 C11 将div指定为“在单个操作中计算 numer / denom 和 numer % denom。”。从 C99 开始,不需要 if (numer &gt;= 0 &amp;&amp; result.rem &lt; 0) 块。
【解决方案3】:

div() 的语义不同于 % 和 / 的语义,这在某些情况下很重要。 这就是为什么以下代码在 psYchotic 的答案中显示的实现中:

if (numer >= 0 && result.rem < 0)
    {
      ++result.quot;
      result.rem -= denom;
    }

% 可能会返回一个否定的答案,而 div() 总是返回一个非负的余数。

检查WikiPedia entry,特别是“div 总是向 0 舍入,这与 C 中的普通整数除法不同,其中负数的舍入取决于实现。”

【讨论】:

  • 这不是真的。 1)当你向零截断时,remainder will be negative if numer &lt; 0。 2) 由于 C11 内置的 /% 保证向零截断,所以 div 被定义为与 /% 做同样的事情。
  • 同意@ybungalobill。 “而 div() 总是返回一个非负的余数。”是不正确的。试试printf("%d\n", div(-7,2).rem); 我希望代码会返回-1
【解决方案4】:

div() 满足了 C99 之前的需求:可移植性

Pre C99a / b 与负操作数的商的舍入方向取决于实现。对于div(),舍入方向不是可选的,而是指定朝向0。div() 提供了统一的可移植除法。 次要的用途是代码需要同时计算商和余数时的潜在效率。

在 C99 及更高版本中,div()/ 指定相同的圆形方向,并且通过更好的编译器优化附近的 a/ba%b 代码,需求减少了。


这是 div() 的令人信服的原因 并且它解释了 C 规范中 udiv_t udiv(unsigned numer, unsigned denom) 的缺失:a/b 与负操作数的实现相关结果的问题是不存在的对于unsigned,即使在 C99 之前。

【讨论】:

    【解决方案5】:

    可能是因为在许多处理器上 div 指令会同时生成这两个值,并且您始终可以依靠编译器来识别相同输入上的相邻 / 和 % 运算符可以合并为一个操作。

    【讨论】:

      【解决方案6】:

      如果您需要这两种价值,则花费更少的时间。 CPU 在执行除法时总是计算余数和商。 如果使用一次“/”和一次“%”,cpu 将计算两次。

      (原谅我英语不好,我不是本地人)

      【讨论】:

      • -1:这并不完全正确,因为编译器可能无论如何都会对其进行优化。此外, div() 必须执行额外的检查以保证结果为非负数。
      • @Jørgen Fogh 断言“div() 必须执行额外检查”并不完全正确。各种处理器提供div() 指定的商和余数,而无需诉诸“额外检查”。这是一个依赖于平台的问题。可能需要或可能需要检查。
      猜你喜欢
      • 1970-01-01
      • 2019-08-10
      • 1970-01-01
      • 2011-06-08
      • 2020-02-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-23
      相关资源
      最近更新 更多