[英]How to divide two 64-bit numbers in Linux Kernel?
Some code that rounds up the division to demonstrate (C-syntax):一些对除法进行四舍五入以演示的代码(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 );
}
Now, if this were User-space we probably wouldn't even notice that our compiler is generating code for those operators (eg divdi3()
for division).现在,如果这是用户空间,我们可能甚至不会注意到我们的编译器正在为这些运算符生成代码(例如divdi3()
用于除法)。 Chances are we link with libgcc
without even knowing it.我们可能在不知情的情况下与libgcc
链接。 The problem is that Kernel-space is different (eg no libgcc
).问题是内核空间是不同的(例如没有libgcc
)。 What to do?该怎么办?
Crawl Google for a while, notice that pretty much everyone addresses the unsigned variant:搜索 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 );
}
I know how to fix this one: Override udivdi3()
and umoddi3()
with do_div()
from asm/div64.h .我知道如何解决这个问题:使用asm/div64.h 中的do_div()
覆盖udivdi3()
和umoddi3()
。 Done right?做对了吗? Wrong.错误的。 Signed is not the same as unsigned, sdivdi3()
does not simply call udivdi3()
, they are separate functions for a reason. Signed 与 unsigned 不同, sdivdi3()
不简单地调用udivdi3()
,出于某种原因,它们是单独的函数。
Have you solved this problem?你解决了这个问题吗? Do you know of a library that will help me do this?你知道有什么图书馆可以帮助我做到这一点吗? I'm really stuck so whatever you might see here that I just don't right now would be really helpful.我真的被困住了,所以无论你在这里看到我现在不知道的任何东西都会非常有帮助。
Thanks, Chad谢谢,乍得
此功能早在内核 v2.6.22 中就已在/linux/lib/div64.c 中引入。
Here's my really naive solution.这是我非常天真的解决方案。 Your mileage may vary.你的旅费可能会改变。
Keep a sign bit, which is sign(dividend) ^ sign(divisor)
.保留一个符号位,即sign(dividend) ^ sign(divisor)
。 (Or *
, or /
, if you're storing your sign as 1 and -1, as opposed to false and true. Basically, negative if either one is negative, positive if none or both are negative.) (或*
或/
,如果您将符号存储为 1 和 -1,而不是 false 和 true。基本上,如果其中一个为负则为负,如果没有或两者均为负则为正。)
Then, call the unsigned division function on the absolute values of both.然后,对两者的绝对值调用无符号除法函数。 Then tack the sign back onto the result.然后将符号重新粘贴到结果上。
PS That is actually how __divdi3
is implemented in libgcc2.c
(from GCC 4.2.3, the version that's installed on my Ubuntu system). PS 这实际上是__divdi3
在libgcc2.c
实现libgcc2.c
(来自 GCC 4.2.3,我的 Ubuntu 系统上安装的版本)。 I just checked.我刚查过。 :-) :-)
ldiv
? ldiv
?
Edit: reread title, so you might want to ignore this.编辑:重读标题,所以你可能想忽略这一点。 Or not, depending on if it has an appropriate non-library version.与否,取决于它是否具有适当的非库版本。
I don't think (at least can't find a way to make) Chris' answer work in this case because do_div() actually changes the dividend in-place.在这种情况下,我不认为(至少找不到办法) 克里斯的回答有效,因为do_div()实际上就地改变了红利。 Getting the absolute value implies a temporary variable whose value will change the way I require but can't be passed out of my __divdi3() override.获取绝对值意味着一个临时变量,它的值将改变我需要的方式,但不能从我的__divdi3()覆盖中传递出去。
I don't see a way around the parameter-by-value signature of __divdi3() at this point except to mimic the technique used by do_div() .除了模仿do_div()使用的技术,我目前看不到__divdi3()的逐个参数签名的方法。
It might seem like I'm bending over backwards here and should just come up with an algorithm to do the 64-bit/32-bit division I actually need.似乎我在这里向后弯腰,应该想出一种算法来进行我实际需要的 64 位/32 位除法。 The added complication here though is that I have a bunch of numerical code using the '/' operator and would need to go through that code and replace every '/' with my function calls.但是,这里增加的复杂性是我有一堆使用“/”运算符的数字代码,并且需要遍历该代码并用我的函数调用替换每个“/”。
I'm getting desperate enough to do just that though.不过,我已经绝望到无法做到这一点。
Thanks for any follow-up, Chad感谢您的跟进,乍得
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.