提问人: 提问时间:8/30/2008 最后编辑:dragosht 更新时间:12/31/2019 访问量:9417
如何在 Linux 内核中除以两个 64 位数字?
How to divide two 64-bit numbers in Linux Kernel?
问:
一些四舍五入的代码来演示(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开始。做对了吗?错。signed 与 unsigned 不同,它不是简单地调用,它们是单独的函数是有原因的。udivdi3()
umoddi3()
do_div()
sdivdi3()
udivdi3()
你解决了这个问题吗?你知道有哪个图书馆可以帮助我做到这一点吗?我真的被困住了,所以无论你在这里看到什么,我现在都没有,都会很有帮助。
谢谢 乍得
答:
ldiv
?
编辑:重新阅读标题,因此您可能希望忽略此内容。是否,取决于它是否具有适当的非库版本。
这是我非常幼稚的解决方案。您的里程可能会有所不同。
保留一个符号位,即 .(或者,或者,如果你将符号存储为 1 和 -1,而不是 false 和 true。基本上,如果其中任何一个是负面的,则为阴性,如果没有,则为正,或者两者都是负面的。sign(dividend) ^ sign(divisor)
*
/
然后,对两者的绝对值调用无符号除法函数。然后将标志重新贴回结果上。
P.S. 这实际上是如何实现的(从 GCC 4.2.3,我的 Ubuntu 系统上安装的版本)。我刚刚检查了一下。:-)__divdi3
libgcc2.c
我不认为(至少找不到一种方法)Chris 的答案在这种情况下有效,因为 do_div() 实际上就地改变了股息。获取绝对值意味着一个临时变量,其值将按照我需要的方式改变,但不能从我的 __divdi3() 覆盖中传递出来。
在这一点上,除了模仿 do_div() 使用的技术之外,我没有看到绕过 __divdi3() 的参数值签名的方法。
看起来我在这里向后弯腰,应该想出一个算法来做我实际需要的 64 位/32 位除法。不过,这里增加的复杂性是,我有一堆使用“/”运算符的数字代码,并且需要遍历该代码并用我的函数调用替换每个“/”。
不过,我越来越绝望了。
感谢您的任何跟进, 乍得
此功能早在内核 v2.6.22 中就在 /linux/lib/div64.c 中引入。
评论
上一个:用 C 语言编写跨平台应用
下一个:使用信号打印奇偶数
评论