gpt4 book ai didi

c - 在移位操作中使用 size_t 进行计数是否合适?

转载 作者:行者123 更新时间:2023-12-02 06:46:22 25 4
gpt4 key购买 nike

这个看似微不足道的小问题最近出现在我的脑海中,但在谷歌搜索了很多之后,我什至找不到关于这个问题的意见。仅提及循环和对象大小。

我知道人们喜欢例子,所以这里是第一个引起问题的例子:

uint64_t deltaSwap( const uint64_t b, const size_t delta, uint64_t mask )
{
return b ^ mask ^ ( mask &= b ^ b >> delta ) << delta;
}

一段时间以来,我一直在尝试对此进行过度优化,我非常清楚这不是编写正确代码的方法,尽管它给了我迄今为止最好的结果,至少在 GCC 中是这样,然后它发生了我。如果你真的想学究气,delta 不应该是 size_t 类型吗?

我从来没有真正理解什么时候使用 size_t,所以我从来没有真正理解过,但如果我理解了,这不是正确的用法吗?

更新:这是对它的作用的简短解释,虽然不是它是如何做的,因为我不太确定如何解释它:

这是一个标准的 delta 交换,这不是一个新的理想,代码工作正常,这不是真正的代码(但既然你问了),我真正做的就是用它做实验,达到最佳性能,您在这里看到的版本是我迄今为止的最佳结果。

代码的目的是交换两位或更多位,如果你想交换第一位和最后一位,可以这样做:

deltaSwap(b, 63, 0x0000000000000001);

或者如果你想颠倒位的顺序:

deltaSwap(b, 32, 0x00000000ffffffff);
deltaSwap(b, 16, 0x0000ffff0000ffff);
deltaSwap(b, 8, 0x00ff00ff00ff00ff);
deltaSwap(b, 4, 0x0f0f0f0f0f0f0f0f);
deltaSwap(b, 2, 0x3333333333333333);
deltaSwap(b, 1, 0x5555555555555555);

尽管对于这个特定任务,deltaswaps 可能不是最好的方法。

更新 2:仅作为补充,这是我能想到的最正确的在线答案(还没得到我的答案),编译器显然完美地优化了它。

uint64_t deltaSwap( const uint64_t b, const uint_fast8_t delta, const uint64_t mask )
{
return b ^ ( mask & ( b ^ b >> delta ) ) ^ ( mask & ( b ^ b >> delta ) ) << delta;
}

我会缩短变量名以使其全部适应我的强制症大脑(显然还有这个网站)强加的 80 个字符,但为了你们所有人,我愿意受苦。

最佳答案

If you really want to be pedantic, shouldn't delta be of type size_t?

不,如果你真的想学究气,delta 应该只是一个无符号整数类型,至少 0sizeof(uint64_t) * CHAR_BIT。在您的例子中是 [0, 63]。没有必要让它成为 size_t

I never really understood when to use size_t, so I never really do, but if I were to, wouldn't this be correct usage?

就代码的正确性而言,还可以。在优化方面,它没有多大意义。 size_t 用于保存大小,因为它是一种保证能够保存对象的最大可能大小的类型。它肯定保证比普通 unsigned 或任何其他无符号整数类型快(请参阅答案底部)。

另一个需要注意的重要事项是:

 b ^ mask ^ ( mask &=  b ^ b >> delta ) << delta

undefined behavior根据 C 标准,因为您在使用变量的值的同时还在同一语句中对其应用了副作用(请参阅第 6.5 段第 2 段,第 76 页 here)。

做你想做的事情的正确方法是:

mask &= b ^ (b >> delta);
return b ^ (mask ^ (mask << delta));

在任何情况下,使用移位运算符时都要格外小心,因为它们优先于其他位运算符。使用额外的括号或将表达式拆分为多行不会影响性能并提高可读性。一个体面的编译器将毫无问题地优化上述内容。


现在,回到您提出这个问题的真正原因:优化。

优化代码的正确方法是让编译器选择您需要的变量的最佳大小。为此,您只需要一个字节,您可以使用 stdint.h 中的 uint_fast8_t,这是最快的(实现定义的)无符号整数类型,宽度至少为8 位。编译器将为其目的选择最快的宽度。

综上所述,优化代码的正确方法是:

uint64_t deltaSwap( const uint64_t b, const uint_fast8_t delta, uint64_t mask )
{
mask &= b ^ (b >> delta);
return b ^ (mask ^ (mask << delta));
}

根据您正在做的事情,如果 GCC 尚未为您内联代码,则将函数声明为 inline __attribute__ ((always_inline)) 也是有意义的,尽管编译器是通常更善于弄清楚何时内联代码,何时不内联代码。您的函数很可能已经内联了。

还有一件更重要的事情:使用正确的优化标志通常比手动调整代码更重要。例如,对于上面的代码,您可能希望使用 -Ofast -march=native 进行编译,甚至可能根据您使用该函数的位置使用其他标志(例如 -ftree-vectorize 如果在循环中使用)。

除上述之外:基准测试、使用 asm() 语句切换到手动调整汇编并查看周围代码是进一步优化上述内容的唯一方法,假设公式为已经简化到它的核心。

关于c - 在移位操作中使用 size_t 进行计数是否合适?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60240007/

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