如何在Linux内核中划分两个64位数字?

时间:2008-08-29 23:22:39

标签: c linux 64-bit

一些代码将代码组合起来演示(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() 。做对了吗?错误。签名与unsigned不同,sdivdi3()_不是简单地调用 udivdi3(),它们是单独的函数。

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

谢谢, 乍得

4 个答案:

答案 0 :(得分:4)

这是我真正天真的解决方案。您的里程可能会有所不同。

保留一个符号位,即sign(dividend) ^ sign(divisor)。 (或者*/,如果你将你的标志存储为1和-1,而不是假和真。基本上,如果任何一个是负数,则为负数,如果没有,则为正数负。)

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

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

答案 1 :(得分:4)

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

答案 2 :(得分:0)

ldiv

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

答案 3 :(得分:0)

我不认为(至少找不到一种方法)Chris' answer在这种情况下工作,因为 do_div() 实际上改变了就地红利。获取绝对值意味着一个临时变量,其值将改变我的要求但不能传递出我的 __ divdi3() 覆盖。

此时我没有看到围绕 __ divdi3() 的逐个参数签名的方法,除非模仿 <使用的技术EM> do_div()

看起来我可能会向后弯腰,应该想出一个算法来实现我实际需要的64位/ 32位除法。这里增加的复杂性是,我有一堆使用'/'运算符的数字代码,需要通过该代码并用函数调用替换每个'/'。

虽然我已经非常绝望了。

感谢您的任何跟进, 乍得