gpt4 book ai didi

c++ - 在 C++ 中进行基本 128 位整数计算的有效方法?

转载 作者:搜寻专家 更新时间:2023-10-31 00:13:21 25 4
gpt4 key购买 nike

几年前,我需要一种方法来使用 Cuda 进行一些基本的 128 位整数数学运算: 128 bit integer on cuda? .现在我遇到了同样的问题,但这次我需要在不支持任何类型的 128 位的 32 位嵌入式系统 (Intel Edison) 上运行一些基本的 128 位算术(求和、位移位和乘法)。但是,直接支持 64 位整数(unsigned long long int)。

我天真地尝试在 CPU 上使用上次回答我的 asm 代码,但是我得到了一堆错误。我真的没有使用 asm 的经验,所以:使用 64 位整数来实现 128 位加法、乘法和位移的最有效方法是什么?

最佳答案

更新:由于 OP 尚未接受答案 ,我附上了更多代码。

使用上面讨论的库可能是个好主意。虽然您今天可能只需要几个功能,但最终您可能会发现还需要一个。然后又是一个。直到您最终编写、调试和维护您自己的 128 位数学库。这是在浪费您的时间和精力。

就是说。如果您决心自己推出:

1) 你之前问的cuda问题已经有了乘法的c代码。有什么问题吗?

2) 这种转变可能不会从使用 asm 中获益,所以 c 解决方案在这里对我来说也很有意义。 虽然如果性能真的是一个问题,我会看看 Edison 是否支持 SHLD/SHRD,这 可能会使速度更快一些。否则,m 也许是这样的方法?

my_uint128_t lshift_uint128 (const my_uint128_t a, int b)
{
my_uint128_t res;
if (b < 32) {
res.x = a.x << b;
res.y = (a.y << b) | (a.x >> (32 - b));
res.z = (a.z << b) | (a.y >> (32 - b));
res.w = (a.w << b) | (a.z >> (32 - b));
} elseif (b < 64) {
...
}

return res;
}

更新:由于 Edison 似乎支持 SHLD/SHRD,这里有一个替代方案,它可能比上面的“c”代码性能更高。对于声称速度更快的所有代码,您应该对其进行测试。

inline
unsigned int __shld(unsigned int into, unsigned int from, unsigned int c)
{
unsigned int res;

if (__builtin_constant_p(into) &&
__builtin_constant_p(from) &&
__builtin_constant_p(c))
{
res = (into << c) | (from >> (32 - c));
}
else
{
asm("shld %b3, %2, %0"
: "=rm" (res)
: "0" (into), "r" (from), "ic" (c)
: "cc");
}

return res;
}

inline
unsigned int __shrd(unsigned int into, unsigned int from, unsigned int c)
{
unsigned int res;

if (__builtin_constant_p(into) &&
__builtin_constant_p(from) &&
__builtin_constant_p(c))
{
res = (into >> c) | (from << (32 - c));
}
else
{
asm("shrd %b3, %2, %0"
: "=rm" (res)
: "0" (into), "r" (from), "ic" (c)
: "cc");
}

return res;
}

my_uint128_t lshift_uint128 (const my_uint128_t a, unsigned int b)
{
my_uint128_t res;

if (b < 32) {
res.x = a.x << b;
res.y = __shld(a.y, a.x, b);
res.z = __shld(a.z, a.y, b);
res.w = __shld(a.w, a.z, b);
} else if (b < 64) {
res.x = 0;
res.y = a.x << (b - 32);
res.z = __shld(a.y, a.x, b - 32);
res.w = __shld(a.z, a.y, b - 32);
} else if (b < 96) {
res.x = 0;
res.y = 0;
res.z = a.x << (b - 64);
res.w = __shld(a.y, a.x, b - 64);
} else if (b < 128) {
res.x = 0;
res.y = 0;
res.z = 0;
res.w = a.x << (b - 96);
} else {
memset(&res, 0, sizeof(res));
}

return res;
}

my_uint128_t rshift_uint128 (const my_uint128_t a, unsigned int b)
{
my_uint128_t res;

if (b < 32) {
res.x = __shrd(a.x, a.y, b);
res.y = __shrd(a.y, a.z, b);
res.z = __shrd(a.z, a.w, b);
res.w = a.w >> b;
} else if (b < 64) {
res.x = __shrd(a.y, a.z, b - 32);
res.y = __shrd(a.z, a.w, b - 32);
res.z = a.w >> (b - 32);
res.w = 0;
} else if (b < 96) {
res.x = __shrd(a.z, a.w, b - 64);
res.y = a.w >> (b - 64);
res.z = 0;
res.w = 0;
} else if (b < 128) {
res.x = a.w >> (b - 96);
res.y = 0;
res.z = 0;
res.w = 0;
} else {
memset(&res, 0, sizeof(res));
}

return res;
}

3) 添加可能受益于 asm.你可以试试这个:

struct my_uint128_t
{
unsigned int x;
unsigned int y;
unsigned int z;
unsigned int w;
};

my_uint128_t add_uint128 (const my_uint128_t a, const my_uint128_t b)
{
my_uint128_t res;

asm ("addl %5, %[resx]\n\t"
"adcl %7, %[resy]\n\t"
"adcl %9, %[resz]\n\t"
"adcl %11, %[resw]\n\t"
: [resx] "=&r" (res.x), [resy] "=&r" (res.y),
[resz] "=&r" (res.z), [resw] "=&r" (res.w)
: "%0"(a.x), "irm"(b.x),
"%1"(a.y), "irm"(b.y),
"%2"(a.z), "irm"(b.z),
"%3"(a.w), "irm"(b.w)
: "cc");

return res;
}

我只是把它搞砸了,所以使用风险自负。我没有 Edison,但这适用于 x86。

更新:如果您只是在进行累加(想想to += from 而不是上面的代码c = a + b ),此代码可能会更好地为您服务:

inline
void addto_uint128 (my_uint128_t *to, const my_uint128_t from)
{
asm ("addl %[fromx], %[tox]\n\t"
"adcl %[fromy], %[toy]\n\t"
"adcl %[fromz], %[toz]\n\t"
"adcl %[fromw], %[tow]\n\t"
: [tox] "+&r"(to->x), [toy] "+&r"(to->y),
[toz] "+&r"(to->z), [tow] "+&r"(to->w)
: [fromx] "irm"(from.x), [fromy] "irm"(from.y),
[fromz] "irm"(from.z), [fromw] "irm"(from.w)
: "cc");
}

关于c++ - 在 C++ 中进行基本 128 位整数计算的有效方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27261291/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com