【问题标题】:Dividing a number represented by two words by a number represented by one? [duplicate]将一个由两个单词表示的数字除以一个由一个表示的数字? [复制]
【发布时间】:2017-07-10 01:57:05
【问题描述】:

我有两个数字,X 和 Y。

Y 是单个无符号整数原语,例如long unsigned int。 (在这种情况下,在执行操作之前没有更大的原语向上转换。)

X由两个原语表示:X0与Y同类型,表示X的低位,X1同类型,表示X的高位。

X / Y 将始终使用与 Y 相同的类型来表示,即可以假设操作不会溢出。 (因为 X 是与 Y 相同类型的两个值的乘积,其中一个值小于或等于 Y。)

确定除法结果的有效方法是什么?

【问题讨论】:

  • 只是一个想法。您可以使用它运行:c = hi_x / y * 2 ^ 64 + lo_x / y; 但您需要考虑hi_x / ylo_x / y 是否没有休息。现在想不出来。为时已晚。
  • 我在您的其他主题中提供了类似问题的链接和解决方案(重复)
  • “高效方式” 速度高效?代码效率高?什么平台?平台是否包含有效的unsigned 除法和有效的unsigned 乘法。 unsigned long 是两次 unsigned 宽度吗?发布您尝试过的内容,即使只是 x/y 以及在“效率”方面与替代代码相比如何。
  • 你应该发布你尝试过的低效方法。
  • 可能是这个链接? stackoverflow.com/questions/1870158/…

标签: c math integer division


【解决方案1】:

您没有指定平台,这对答案至关重要。

X / Y 将始终使用与 Y 相同的类型来表示,即操作可以假设不会溢出。 (因为 X 是同一类型的两个值的乘积 为Y,其中一个小于或等于Y。)

在 x86-64 架构上,您可以利用这一事实,通过除以 RDX:RAX 对,因此它实际上与您将一个“粘合”的 128 位寄存器用于除数相同。但请注意,如果上述不变量并不总是成立,那么您将从 CPU 获得 除法异常

也就是说,一种实现是使用内联汇编,例如:

/* divides x1:x0 pair by y, assumes that quotient <= UINT64_MAX  */
uint64_t udiv128_64_unsafe(uint64_t x0, uint64_t x1, uint64_t y)
{
    __asm__ (
        "divq\t%3"
        : "=a" (x0)
        : "0" (x0), "d" (x1), "rm" (y)
    );
    return x0;
}

哪个 GCC 6.3.0 翻译得很好(-O1):

udiv128_64_unsafe:
        mov     rcx, rdx            ; place the y (divisor) in RCX 
        mov     rax, rdi            ; low part of the dividend (x0)
        mov     rdx, rsi            ; high part of the divided (x1)
        divq    rcx                 ; RAX = RDX:RAX / RCX
        ret                         ; RAX is return value

例如,对于X = 65454567423355465643444545Y = 86439334393432232

#include <stdio.h>
#include <inttypes.h>

uint64_t udiv128_64_unsafe(uint64_t x0, uint64_t x1, uint64_t y) { ... }

int main(void)
{
    printf("%" PRIu64 "\n", udiv128_64_unsafe(0x35c0ecb3fea1c941ULL, 0x36248bULL,
        86439334393432232ULL));
    return 0;
}

给定的测试驱动程序产生:

757231275

【讨论】:

    【解决方案2】:

    gcc 具有用于 x86 架构的 __int128unsigned __int128。我过去曾成功使用它来执行您描述的此类操作。我相信所有主要的编译器都有对应的。

    【讨论】:

    • 我没有这个选项。
    • @Pineapple 为什么?
    【解决方案3】:

    “将 2 位数字除以 1 位,给出 1 位商和余数”是合成更大除法所需的基本原语。如果您的硬件中没有它(使用 digit == unsigned long int),则需要使用较小的数字。

    在您的情况下,将 Y 拆分为 2 个半长整数,将 X 拆分为 4 个半长整数,然后以这种方式进行除法。

    【讨论】:

    • 这是我最终追求的方法 - 当我有机会完成代码时,我会发布解决方案。
    • @Pineapple:您需要正确舍入的商吗?如果不是,那么牛顿的方法可能比完整的多词划分更快、更容易。诚然,Knuth 的算法 D 在这种有限的情况下确实有所简化,但我的口味仍然有点复杂。
    猜你喜欢
    • 2015-04-02
    • 1970-01-01
    • 2012-04-27
    • 1970-01-01
    • 1970-01-01
    • 2018-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多