【问题标题】:How to divide two 64-bit numbers in Linux Kernel?如何在 Linux 内核中划分两个 64 位数字?
【发布时间】:2010-09-07 07:41:09
【问题描述】:

一些代码将除法四舍五入进行演示(C 语法):

#define SINT64 long long int
#define SINT32 long int

SINT64 divRound(SINT64 dividend, SINT64 divisor)
{
  SINT32 quotient1 = dividend / divisor;

  SINT32 modResult = dividend % divisor;
  SINT32 multResult = modResult * 2;
  SINT32 quotient2 = multResult / divisor;

  SINT64 result = quotient1 + quotient2;

  return ( result );
}

现在,如果这是用户空间,我们可能甚至不会注意到我们的编译器正在为这些运算符生成代码(例如,divdi3() 用于除法)。我们可能会在不知情的情况下与libgcc 链接。问题是内核空间不同(例如没有libgcc)。怎么办?

在 Google 上爬了一会儿,注意到几乎每个人都提到了未签名的变体:

#define UINT64 long long int
#define UINT32 long int

UINT64 divRound(UINT64 dividend, UINT64 divisor)
{
  UINT32 quotient1 = dividend / divisor;

  UINT32 modResult = dividend % divisor;
  UINT32 multResult = modResult * 2;
  UINT32 quotient2 = multResult / divisor;

  UINT64 result = quotient1 + quotient2;

  return ( result );
}

我知道如何解决这个问题:用 asm/div64.h 中的 do_div() 覆盖 udivdi3()umoddi3()。做对了吗?错误的。有符号与无符号不同,sdivdi3() 不只是简单地调用udivdi3(),它们是独立的函数是有原因的。

你解决了这个问题吗?你知道可以帮助我做到这一点的图书馆吗?我真的被困住了,所以无论你在这里看到什么我现在没有看到的都会很有帮助。

谢谢, 乍得

【问题讨论】:

    标签: c linux 64-bit


    【解决方案1】:

    ldiv?

    编辑:重读标题,所以你可能想忽略它。与否,取决于它是否具有适当的非库版本。

    【讨论】:

      【解决方案2】:

      此功能早在内核 v2.6.22 中就已在 /linux/lib/div64.c 中引入。

      【讨论】:

      • 最近我们得到了一份 libgcc 实现的副本,供每个代码使用(在 lib/libgcc IIRC 下)。但是内核中的旧方法确实是 do_div()div64.c 中的相应函数。
      【解决方案3】:

      我不认为(至少找不到方法)Chris' answer 在这种情况下工作,因为 do_div() 实际上改变了股息-地方。获取绝对值意味着一个临时变量,其值将改变我需要的方式,但不能从我的 __divdi3() 覆盖中传递出去。

      除了模仿 do_div().

      我似乎在这里向后弯腰,应该想出一个算法来进行我实际需要的 64 位/32 位除法。不过,这里增加的复杂性是我有一堆使用“/”运算符的数字代码,并且需要遍历该代码并用我的函数调用替换每个“/”。

      不过,我已经迫不及待地想要这么做了。

      感谢您的跟进, 乍得

      【讨论】:

        【解决方案4】:

        这是我非常幼稚的解决方案。您的里程可能会有所不同。

        保留一个符号位,即sign(dividend) ^ sign(divisor)。 (或*,或/,如果您将符号存储为1 和-1,而不是假和真。基本上,如果其中一个为负数,则为负数,如果没有一个或两者均为负数,则为正数。)

        然后,对两者的绝对值调用无符号除法函数。然后将标志重新粘贴到结果上。

        附:这实际上是在libgcc2.c 中实现__divdi3 的方式(来自GCC 4.2.3,安装在我的Ubuntu 系统上的版本)。我刚检查过。 :-)

        【讨论】:

          猜你喜欢
          • 2015-05-19
          • 1970-01-01
          • 1970-01-01
          • 2018-07-30
          • 2011-07-10
          • 1970-01-01
          • 1970-01-01
          • 2013-08-21
          • 2012-11-30
          相关资源
          最近更新 更多