- 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/
我想将这个无符号数:1479636484000 向右移动 7 位。这在 JavaScript 中可能吗? 两者 1479636484000 >> 7 和 1479636484000 >>> 7 返回错
鉴于以下代码: import matplotlib.pyplot as plt import numpy as np x = [1.0, 1.1, 2.0, 5.7] y = np.arange(le
我有一个低级键盘钩子(Hook),目前允许我从任何应用程序(包括游戏)中控制媒体播放器。 它通过查看捕获的特定击键来工作。 我想扩展它以查找键的组合。我可以对一些逻辑进行硬编码,但我觉得必须有一种更合
我需要一些帮助来理解这段C代码。我不知道这里的“L”和“\”是什么?请也说明一点:) #define l2n(l,c) (*((c)++)=(unsigned char)(((l)>>2
我正在查看一段代码: int result = 0 ; char byte = foo[j] for (i = 7 ; i>0 ; i--) { byte = (byte & ~0x1)>>1
我们有一个项目要求我们编写一个程序,允许用户输入一系列数字“将数字读入数组以进行进一步处理,用户通过输入负数表示他们已完成(负数不用于计算),在读取所有数字后执行以下操作,总结输入的#,计算输入的#,
锁定。有disputes about this question’s content正在解决中。它目前不接受新的答案或互动。 def menu(): choice = input("Pres
为什么如果 int x = -1 // binary: 11111111111111111111111111111111 x = x >>> 31; 我们有 000000000000000000000
我的问题其实应该很简单:我有一个玩家对象数组。(玩家[])我想要一个函数来旋转这个数组直到一个索引: public void rotateArray(Object[] array, int index
我有一个编码为 boost 动态位集的数字列表。我根据此列表中的任何数字可以采用的最大值动态选择此位集的大小。所以假设我有从 0 到 7 的数字,我只需要三位,我的字符串 0,2,7 将被编码为000
我能想到一些令人讨厌的低效方法来完成这项任务,但我想知道最好的方法是什么。 例如,我想复制一个字节中从第 3 位开始的 10 个字节,并像往常一样复制到一个指针。 有没有比一次复制一个移位字节更好的方
我正在尝试为该问题添加更多规则,并且该规则一直给我带来这种转变/减少冲突的能力,我不知道为什么会这样做,并且在过去的24小时内我一直在尝试解决问题 FuncDecl : RetTyp
This question already has answers here: Why does it make a difference if left and right shift are us
我在 Perl 中遇到这个问题已经有几天了,在搜索了无数的手册页、perldocs 和谷歌搜索了太多的搜索词之后,希望这里有人能帮助我。 我得到两个表示十六进制值的字符串,即“FFFF”,而不是 Pe
我有一个主 div,两个 div 水平并排放置在这个父 div 中。 .parent{ height: 360px; margin-top: 0px; bo
我想 float 我的元素列表并从第二个元素创建一个移动效果。 如何避免第二个 .item 之后的“清除”行为? .shift { float: right; width: 50%;
我正在使用 SSE3 优化我的代码。代码中有一点迫使我将 vector 中的所有元素移动一个元素 v[0] = 0 //v is some char* and N = v.size() for(i
.file "calcnew.c" .text .globl calcnew .type calcnew, @function calcnew:
我有一个点对象: class Point { final int x,y; ... } 因为这些点将在我的代码中到处使用/创建,所以我想开始使用 guavas 缓存。不幸的是
x = "Foo 890 bar *()" 如何将包括 "*()" 在内的小写字母“未移位”返回到 890?期望的结果: foo 890 bar 890 不需要的: x.lower() => "foo
我是一名优秀的程序员,十分优秀!