10

一些代码将除法四舍五入来演示(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不知情的情况下与之联系。问题是内核空间不同(例如 no 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 );
}

我知道如何解决这个问题: Override udivdi3()and umoddi3()with do_div()from asm/div64.h。做对了吗?错误的。有符号与无符号不同,sdivdi3()不只是调用udivdi3(),它们是独立的函数是有原因的。

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

谢谢,乍得

4

4 回答 4

5

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

于 2008-10-12T21:52:44.870 回答
4

这是我非常天真的解决方案。你的旅费可能会改变。

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

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

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

于 2008-08-29T23:45:58.797 回答
0

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

除了模仿 do_div() 使用的技术外,目前没有看到绕过__divdi3()的参数值签名的方法。

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

不过,我已经迫不及待地想要这样做了。

感谢您的跟进,乍得

于 2008-09-02T16:06:26.620 回答
0

ldiv?

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

于 2008-08-29T23:31:28.533 回答