简体   繁体   English

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

[英]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 这实际上是__divdi3libgcc2.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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM