我从三个值A,B,C(无符号的32位整数)开始。而且我必须获得两个值D,E(也是32位无符号整数)。哪里

D = high(A*C);
E = low(A*C) + high(B*C);

我希望两个32位uint相乘会产生64位结果。 “高”和“低”只是我对标记64位乘法结果中的前32位和后32位的 promise 。

我尝试获得一些已经可用的功能的优化代码。我在巨大的循环中只有一小段代码,只有几个命令行,但是它几乎消耗了所有的计算时间(用于数小时计算的物理模拟)。这就是为什么我尝试优化这一小部分的原因,而其余的代码可以保持“用户精心安排”。

有一些SSE指令适用于上述计算例程。 gcc编译器可能会优化工作。但是,如果有必要,我不会拒绝直接在SSE指令中编写一些代码的选项。

请耐心等待我对SSE的经验不足。我将尝试仅象征性地为SSE写一个算法。订购掩膜或理解结构可能会出现一些错误。
  • 将四个32位整数按顺序存储到一个128位寄存器中:A,B,C,C。
  • 将指令(可能是pmuludq)应用到上述的128位寄存器中,该寄存器将32位整数对相乘并返回64位整数对。因此,它应该同时计算A*C的乘法和B*C的乘法,并返回两个64位值。
  • 我希望我有新的128位寄存器值P,Q,R,S(四个32位块),其中P,Q是A*C的64位结果,而R,S是B*C的64位结果。然后我继续将寄存器中的值重新排列为P,Q,0,R
  • 取前64位P,Q,再加后64位0,R。结果是一个新的64位值。
  • 将结果的前32位读取为D,将结果的后32位读取为E。

  • 此算法应返回E和D的正确值。

    我的问题:

    c++中是否有静态代码生成类似于1-5 SSE算法的SSE例程?我提供具有更高性能的解决方案。如果该算法对标准C++命令有问题,是否有办法在SSE中编写算法?

    我使用TDM-GCC 4.9.2 64位编译器。

    (注:问题在咨询后被修改)

    (注2:我在此http://sci.tuomastonteri.fi/programming/sse中的灵感来自于使用SSE获得更好的性能)

    最佳答案

    如果我理解正确,则需要计算A * B中潜在的溢出次数。如果是,那么您有2个不错的选择-“使用两倍大的变量”(为uint64写128位数学函数-并不难(或等我明天发布))和“使用浮点类型”:
    (浮点数(A)*浮点数(B))/浮点数(C)
    因为精度损失最小(假设float为4字节,double为8字节,long为16字节长),并且float和uint32都需要4字节内存(对uint64_t使用double,因为它应该为8字节长):

    #include <iostream>
    #include <conio.h>
    #include <stdint.h>
    
    using namespace std;
    
    int main()
    {
        uint32_t a(-1), b(-1);
        uint64_t result1;
        float result2;
        result1 = uint64_t(a)*uint64_t(b)/4294967296ull;    // >>32 would be faster and less memory consuming
        result2 = float(a)*float(b)/4294967296.0f;
        cout.precision(20);
        cout<<result1<<'\n'<<result2;
        getch();
        return 0;
    }
    

    产生:
    4294967294
    4294967296
    

    但是,如果您想要真正准确正确的答案,我建议您使用两倍大的类型进行计算

    现在,我想到了-您可以为uint64使用long double并为uint32使用double,而不是为uint64编写函数,但是我认为不能保证long double将为128bit,因此您必须进行检查。我会选择更通用的选择。

    编辑:
    You can write function to calculate that without using anything more
    than A, B and result variable which would be of the same type as A.
    Just add rightmost bit of (where Z equals B*(A>>pass_number&1)) Z<<0,
    Z<<1, Z<<2 (...) Z<<X in first pass, Z<<-1, Z<<0, Z<<1 (...) Z<<(X-1)
    for second (there should be X passes), while right shifting the result
    by 1 (the just computed bit becomes irrelevant to us after it's
    computed as it won't participate in calculation anymore, and it would
    be erased anyway after dividing by 2^X (doing >>X)
    

    (必须放在“代码”中,因为这是我的新手,无法找到另一种方法来防止格式化脚本吃掉一半)

    这只是一个简单的想法。您必须检查它的正确性(对不起,但是我现在真的很累-但是结果在任何计算点都不应溢出,因为如果我正确的话,最大进位值为2倍,并且算法本身似乎很好)。

    如果您仍然需要帮助,明天我将为您编写代码。

    关于c++ - 得到一个整数的高半部分和低半部分的乘积,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/35160244/

    10-16 04:35