- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
这个看似微不足道的小问题最近出现在我的脑海中,但在谷歌搜索了很多之后,我什至找不到关于这个问题的意见。仅提及循环和对象大小。
我知道人们喜欢例子,所以这里是第一个引起问题的例子:
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 typesize_t
?
不,如果你真的想学究气,delta
应该只是一个无符号整数类型,至少 0
到 sizeof(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/
error C2664: 'errno_t wcstombs_s(size_t *,char *,size_t,const wchar_t *,size_t)' : cannot convert pa
size_t有什么区别和 std::size_t在声明它们的位置,何时应该使用它们以及任何其他差异化功能方面? 最佳答案 C的size_t和 C++ 的 std::size_t都是一样的。 在 C 中
刚读完: Does "std::size_t" make sense in C++? 我意识到使用 ::size_t不符合标准(虽然我的编译器支持)当你#include .我想遵守标准,但我不想在前
有什么理由不假设 SIZE_T 是 Microsoft 的 Visual C/C++ 编译器上 size_t 的类型定义? Windows intsafe.h 函数确实包括从一个函数到另一个函数的安全
size_t 和 std::size_t 在声明的位置、应在何时使用以及任何其他区别特性方面有何区别? 最佳答案 C 的 size_t和 C++ 的 st
在某些 Windows API 调用中,我得到:cannot convert argument 6 from 'size_t *' to 'SIZE_T *' . This answer告诉我SIZE
将迭代器条件右操作数从 size_t 转换为 int 更好,还是迭代可能超过 int 的最大值?答案实现具体吗? int a; for (size_t i = 0; i (i)) (有关 numeri
我尝试了三个连续的行(每个单独一个),但是没有一个起作用。 为什么?? int main() { size_t j{8}; char arr[static_cast(j)]={'t'}
我的 C++ 知识一塌糊涂。我有 Apple 提供的代码,他们像往常一样提供了不完整的解决方案。 在此代码中,他们提供了两个空的方法 header : - (NSString *)encodeBase
这是证据: inline constexpr std::size_t prev(std::size_t i) { --i; return i; } int main() { s
我对 size_t 的某些行为感到困惑我注意到: size_t zero = 0x1 << 32; size_t big = 0x1 << 31; size_t not_as_big = 0x1 <<
size_t 在哪里什么时候我什么都没有? 总是假设 size_t 是否合理? == std::size_t ? 什么时候应该使用 size_type在 std容器(string::size_type
我在为 32 位编译时遇到此错误。相同的文件在 64 位 Windows 上编译没有错误 1>c:\project\test.cpp(1317) : error C2664: 'StringCbCop
我希望只有一个模板函数。所以我想到了…… template > || std::is_same_v > > > std::ostream& op
我正在使用 Visual Studio 2017 社区版。它允许我在没有适当包含的情况下同时使用 size_t 和 std::size_t。它似乎适用于大多数 std 库。我认为这是因为图书馆本身的一
我可能要疯了,但我认为我从未在 C++ 中看到过这种情况(尽管我的引用代码是在 C 中)。为什么这里代码的返回值上有一个static,有什么影响?我认为我从未见过类范围之外的静态函数(但显然 C 没有
它没有在 std::string 中明确列出 constructor doc ,(编辑: 这里的人说我应该引用实际的 cppreference 而不是 cplusplus.com)但显然它有效。这意味
将 -1 分配给 size_t 类型的变量 t 并检查它与 -1 和 4294967295(FFFFFFFF,2 对-1 的补充;我的系统是64 位;值可能因系统而异),那么在这两种情况下,它都返回
我正在实现循环数组数据结构,其代码如下所示: struct CircularArrayException : public std::exception { std::string msg;
这个问题在这里已经有了答案: how to pass 2 dimensional array if both dimensions are unknown at compile time (5 个答
我是一名优秀的程序员,十分优秀!