如何在Linux内核中除以两个64位数字?

c linux 64-bit

8827 观看

4回复

0 作者的声誉

一些代码将除法进行四舍五入来演示(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(),由于某种原因,它们是独立的函数。

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

谢谢,乍得

作者: Chad 的来源 发布者: 2008 年 8 月 29 日

回应 (4)


0

985 作者的声誉

ldiv

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

作者: Mat Noguchi 发布者: 29.08.2008 11:31

4

188152 作者的声誉

这是我真正的天真解决方案。你的旅费可能会改变。

保留一个符号位,即sign(dividend) ^ sign(divisor)。(或*,或/,如果将符号存储为1和-1,则与false和true相反。基本上,如果其中一个为负,则为负;如果两个都不为负,则为正。)

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

PS实际上__divdi3是这样实现的libgcc2.c(从我的Ubuntu系统上安装的版本GCC 4.2.3)。我刚刚检查。:-)

作者: Chris Jester-Young 发布者: 29.08.2008 11:45

0

0 作者的声誉

在这种情况下,我认为(至少无法找到一种方法)克里斯的答案有效,因为do_div()实际上就地更改了股息。获取绝对值意味着一个临时变量,该变量的值将更改我需要的方式,但不能从__divdi3()重写中传递出去。

除了模仿do_div()所使用的技术外,我目前还没有办法解决__divdi3()的按值签名的问题

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

我正拼命地做到这一点。

感谢您的后续行动,乍得

作者: Chad 发布者: 02.09.2008 04:06

4

165 作者的声誉

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

作者: colgur 发布者: 12.10.2008 09:52
32x32