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

How to divide two 64-bit numbers in Linux Kernel?

提问人: 提问时间:8/30/2008 最后编辑:dragosht 更新时间:12/31/2019 访问量:9417

问:

一些四舍五入的代码来演示(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()libgcclibgcc

抓取 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开始。做对了吗?错。signed 与 unsigned 不同,它不是简单地调用,它们是单独的函数是有原因的。udivdi3()umoddi3()do_div()sdivdi3()udivdi3()

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

谢谢 乍得

C Linux 64 位

评论


答:

0赞 Mat Noguchi 8/30/2008 #1

ldiv?

编辑:重新阅读标题,因此您可能希望忽略此内容。是否,取决于它是否具有适当的非库版本。

4赞 C. K. Young 8/30/2008 #2

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

保留一个符号位,即 .(或者,或者,如果你将符号存储为 1 和 -1,而不是 false 和 true。基本上,如果其中任何一个是负面的,则为阴性,如果没有,则为正,或者两者都是负面的。sign(dividend) ^ sign(divisor)*/

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

P.S. 这实际上是如何实现的(从 GCC 4.2.3,我的 Ubuntu 系统上安装的版本)。我刚刚检查了一下。:-)__divdi3libgcc2.c

0赞 Chad 9/3/2008 #3

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

在这一点上,除了模仿 do_div() 使用的技术之外,我没有看到绕过 __divdi3() 的参数值签名的方法。

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

不过,我越来越绝望了。

感谢您的任何跟进, 乍得

5赞 colgur 10/13/2008 #4

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

评论

0赞 0andriy 8/7/2018
最近,我们得到了每个要使用的代码的 libgcc 实现的副本(在 lib/libgcc IIRC 下)。但是内核中的旧方法确实是 do_div()div64.c 中的相应函数。