在 HLSL 中进行 64 位加法,为啥我的一种实现会产生不正确的结果?

Posted

技术标签:

【中文标题】在 HLSL 中进行 64 位加法,为啥我的一种实现会产生不正确的结果?【英文标题】:Doing 64bit addition in HLSL, why is one of my implementations producing incorrect results?在 HLSL 中进行 64 位加法,为什么我的一种实现会产生不正确的结果? 【发布时间】:2015-10-18 07:42:39 【问题描述】:

我在 HLSL 中有 2 个 64 位添加的不同实现。如果我想设置 A += B,其中 al、ah、bl 和 bh 分别是 A 和 B 的低 32 位和高 32 位,那么我可以这样做

(1):

#define pluseq64(al, ah, bl, bh) do \
    uint tadd0 = al >> 1;\
    uint tadd1 = bl >> 1;\
    tadd0 += al & bl & 0x00000001;\
    tadd0 += tadd1;\
    tadd0 >>= 31;\
    al += bl;\
    ah += bh;\
    ah += tadd0;

或(2):

#define pluseq64(al, ah, bl, bh) do \
    uint t = al;\
    al += bl;\
    ah += bh;\
    if (al < t)  \
        ah += 1; \
      while(0)

现在,有趣的是,(1) 总是产生正确的输出,而 (2) 不会。鉴于(1)是一种混乱的操作(3个班次,5个加法来做一个64位+=),我更喜欢沿着(2)到(1)的路线,除了(2)不能正常工作。

作为 (2) 的替代方法,我尝试过:

#define pluseq64(al, ah, bl, bh) do \
    uint t = al;\
    al += bl;\
    ah += bh;\
    ah += (al < t);  while(0)

这也不太有效(可能出于相同的原因,不管那个原因是什么,如果我有我的猜测的话)。

为什么 (2) 不能正常工作?奖励:有没有更好的方法在 HLSL 中添加 64 位?

谢谢!

【问题讨论】:

出错的输入是什么? 我可能需要一些时间才能准确找到它偏离的位置(GPU 内部没有断点功能,等等)。有趣的是,当我放入一些存在进位位的测试用例时,两个版本都产生了正确的输出......但问题仍然是,当我使用版本 1 和版本 2 时,累积输出是不同的。就是这样奇怪。 【参考方案1】:

在我的测试中,这三个似乎在 C++ 上产生了相同的输出,所以这有点奇怪。您是否进行了 CPU 端测试并在那里为您工作?您可以尝试的一件事是跳过宏 & do/while 的东西,看看它是否适用于一个简单的 HLSL 函数:

void pluseq64(inout uint al, inout uint ah, in bl, in bh)

    uint t = al;
    al += bl;
    ah += bh;
    if (al < t)
    
        ah += 1;
    
    // or "ah += uint(al < t); 

无论如何,函数在 HLSL 中是内联的,所以我认为您不会从使用预处理器指令中获得任何好处。

【讨论】:

【参考方案2】:

也许您的 sn-p 显示了一个较旧的驱动程序错误?使用PIX 逐步完成反汇编可能会有所帮助。我在 Nvidia/AMD/Intel 上使用了以下没有问题,基本上等同于您的 (1)。

struct uint64_emulated

    uint32_t low;
    uint32_t high;


inline uint64_emulated Add(uint64_emulated a, uint64_emulated b)

    uint64_emulated c;
    c.low = a.low + b.low;
    c.high = a.high + b.high + (c.low < a.low); // Add with carry.
    return c;


【讨论】:

以上是关于在 HLSL 中进行 64 位加法,为啥我的一种实现会产生不正确的结果?的主要内容,如果未能解决你的问题,请参考以下文章

Delphi - 为啥我不能在 64 位中安装我的组件?

为啥我的64位jdk装好后cmd显示32位,怎么改啊

keil MDK-ARM 如何实现64位加法

为啥 MySQLdb 安装无法在我的 64 位 Mac 上运行

为啥在进行 64 位操作时编译器会发生变化?

AAch64 高级 SIMD 向量加法