C# 将布尔值转换为字节的最快方法是什么?
将布尔值转换为字节的最快方法是什么 我想要这个映射:False=0,True=1 注意:我不想使用任何C# 将布尔值转换为字节的最快方法是什么?,c#,C#,将布尔值转换为字节的最快方法是什么 我想要这个映射:False=0,True=1 注意:我不想使用任何if语句或其他条件语句。我不希望CPU停止或猜测下一个语句 更新: 对于那些想了解这个问题要点的人。 此示例显示如何从代码中减少两条if语句 byte A = k > 9 ; //If it was possible (k>9) == 0 || 1 c[i * 2] = A * (k + 0x37) - (A - 1) * (k + 0x30); 那么: byte x = valu
if
语句或其他条件语句。我不希望CPU停止或猜测下一个语句
更新:
对于那些想了解这个问题要点的人。
此示例显示如何从代码中减少两条if语句
byte A = k > 9 ; //If it was possible (k>9) == 0 || 1
c[i * 2] = A * (k + 0x37) - (A - 1) * (k + 0x30);
那么:
byte x = value ? (byte) 1 : (byte) 0;
如果你说的是最有效的方法,那么可能有一些不安全代码的技巧。。。但这真的是你的瓶颈吗
编辑:我刚刚意识到,条件运算符需要对操作数进行这些强制转换,以便使整个表达式成为一个字节
编辑:看到你的问题后,在IMO中有一种更好的优化方法。目前,你将执行不需要任何一种方法的操作。请尝试以下方法:
c[i << 1] = k > 9 ? k + 0x37 : k + 0x30;
请注意,在我的计算机上,这确实为sum
提供了相同的值,但我根本不确定它是否能保证。我不知道是否有任何保证可以保证的内存表示形式为true
。。。因此,在某些CLR上,您可能会得到错误的答案
然而,我要指出的是,在我的笔记本电脑上,这个1亿次操作的循环只需要大约300毫秒(这包括增加总和和初始阵列访问,这可能需要大量时间,特别是由于缓存未命中)。。。你真的确定这是瓶颈吗?您希望如何以如此快的速度获取要散列的数据,从而成为问题
编辑:我刚刚添加了另一个循环以查看“基本案例”:
for(int j=0;j
这需要大约一半的时间。。。因此,实际上只有一半的时间花在特定于散列的代码上。你真的,真的确定这是以可读性和潜在正确性为代价进行优化的关键代码吗?
byte x = Convert.ToByte(true);
如果myBool为False,则为0;如果为True,则为1。使用
unsafe
code此方法速度非常快。通过优化,其速度比条件运算符快约30%
bool input = true;
byte value = *((byte*)(&input)); // 1
//警告!大脑提前编译代码!
静态只读字符[]HexChars={0',1',2',3',4',5',6',7',8',9',A',B',C',D',E',F'};
公共静态字符串ToHex(此字节[]me)
{
如果(me==null)返回null;
int ml=me.Length;
char[]c=新字符[2*ml];
int cp=0;
对于(int i=0;i>4];
}
返回新字符串(c);
}
以下是一个比较三个选项的简单基准:
Int32 j = 0;
bool b = true;
for (int n = 0; n < 5; n++) {
Stopwatch sw1 = new Stopwatch();
Stopwatch sw2 = new Stopwatch();
Stopwatch sw3 = new Stopwatch();
sw1.Start();
for (int i = 100 * 1000 * 1000; i > 0; i--)
unsafe { j = *(int*)(&b); }
sw1.Stop();
sw2.Start();
for (int i = 100 * 1000 * 1000; i > 0; i--)
j = b ? 1 : 0;
sw2.Stop();
sw3.Start();
for (int i = 100 * 1000 * 1000; i > 0; i--)
j = Convert.ToInt32(b);
sw3.Stop();
Trace.WriteLine("sw1: " + sw1.ElapsedMilliseconds +
" sw2:" + sw2.ElapsedMilliseconds + ", +" + 100 * (sw2.ElapsedMilliseconds - sw1.ElapsedMilliseconds) / sw1.ElapsedMilliseconds + "% relative to sw1" +
" sw3:" + sw3.ElapsedMilliseconds + ", +" + 100 * (sw3.ElapsedMilliseconds - sw1.ElapsedMilliseconds) / sw1.ElapsedMilliseconds + "% relative to sw1"
);
}
结论:
不安全的方法比其他两种方法快25%左右
“if”版本的相对缓慢是由于分支的高成本造成的。
如果Microsoft在编译时进行转换,则可以避免转换成本。手写IL:
.method private hidebysig static
int32 BoolToInt (
bool b
) cil managed noinlining
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldc.i4.0
IL_0002: cgt.un
IL_0004: ret
}
而且,它们被一些x86代码所JIT:(clrjit.dll版本4.7.3131.0)
唯一的问题是,我没有找到在C#中内联IL的简单方法。这个答案是使用dnSpy完成的。您可以使用此结构执行类似于Chaospanion解决方案的操作,但使用安全代码
[StructLayout(LayoutKind.Explicit)]
struct BoolByte
{
[FieldOffset(0)]
public bool flag;
[FieldOffset(0)]
public byte num;
}
...
bool someBool = true;
byte num = new BoolByte() { flag = someBool }.num;
我还没有对它进行基准测试,所以我不确定速度如何比较
[编辑]我用与.NET 3.5相当的mono运行了基准测试,它看起来比普通的if检查(在我的macbook pro上)慢约10%。所以忘了这个吧。我怀疑.NET 4+在这方面会有什么不同。由于.NET Core 2.1,您可以将
bool
重新解释为字节。这是无分支的,应该非常快,因为它几乎不需要“做”任何事情
从技术上讲,true
值可以是任何非零的字节
,但实际上它是1
。这值得考虑。如果您想要绝对的确定性,您可以寻找一种有效的、无分支的方法,将一个字节转换为非零的1
,或者将其保留为0
。(想到两种方法:A)涂抹位,使所有位都是0
或所有位都是1
,然后执行&1
以获得0
或1
。B) 将0-n
作为int
,它将是零或负。移动符号位,使其成为最低有效位,从而产生0
或1
)是否使用了反射镜?这就是公共静态字节ToByte(bool值){if(!value){return 0;}return 1;}@Vilx-:那么OP不能同时拥有它?1:0实际上对你来说太慢了,那么你真的需要重新检查一下你想做什么。如果该级别的转换每秒发生数千万次(这是它显著影响性能的唯一方式),那么为什么不在ASM或其他版本中编写呢?这是你能显著击败x的唯一方法?1:0
表示速度。有趣的是,条件“需要优化”中至少有一个(可能有两个)不必要的倍数;-)(但在一天结束的时候……它。只是。没关系。)另一种方法可能是使用switch,它可以作为单个跳转进行优化——不确定是C#还是JIT实现了这一点。另一种方法是查找表。唷!:)@埃米尔:别人指出你找错了人,这是完全正确的,而且经常是有用的。没有人试图不专业地对待你;你有很多人试图给你建议,这样你就可以a)不把时间浪费在毫无意义的优化上,b)更有效地使用这个网站。我们中的许多人都惊讶地看到有人问这个问题,这可能会在我们的评论中出现。但是如果你是从一个否定的角度读的
bool input = true;
byte value = *((byte*)(&input)); // 1
// Warning! Brain-compiled code ahead!
static readonly char[] HexChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
public static string ToHex(this byte[] me)
{
if ( me == null ) return null;
int ml = me.Length;
char[] c = new char[2*ml];
int cp = 0;
for (int i = 0; i < ml; i++ )
{
c[cp++] = HexChars[me[i]&15];
c[cp++] = HexChars[me[i]>>4];
}
return new string(c);
}
Int32 j = 0;
bool b = true;
for (int n = 0; n < 5; n++) {
Stopwatch sw1 = new Stopwatch();
Stopwatch sw2 = new Stopwatch();
Stopwatch sw3 = new Stopwatch();
sw1.Start();
for (int i = 100 * 1000 * 1000; i > 0; i--)
unsafe { j = *(int*)(&b); }
sw1.Stop();
sw2.Start();
for (int i = 100 * 1000 * 1000; i > 0; i--)
j = b ? 1 : 0;
sw2.Stop();
sw3.Start();
for (int i = 100 * 1000 * 1000; i > 0; i--)
j = Convert.ToInt32(b);
sw3.Stop();
Trace.WriteLine("sw1: " + sw1.ElapsedMilliseconds +
" sw2:" + sw2.ElapsedMilliseconds + ", +" + 100 * (sw2.ElapsedMilliseconds - sw1.ElapsedMilliseconds) / sw1.ElapsedMilliseconds + "% relative to sw1" +
" sw3:" + sw3.ElapsedMilliseconds + ", +" + 100 * (sw3.ElapsedMilliseconds - sw1.ElapsedMilliseconds) / sw1.ElapsedMilliseconds + "% relative to sw1"
);
}
sw1: 172 sw2:218, +26% relative to sw1 sw3:213, +23% relative to sw1
sw1: 168 sw2:211, +25% relative to sw1 sw3:211, +25% relative to sw1
sw1: 167 sw2:212, +26% relative to sw1 sw3:208, +24% relative to sw1
sw1: 167 sw2:211, +26% relative to sw1 sw3:209, +25% relative to sw1
sw1: 167 sw2:212, +26% relative to sw1 sw3:210, +25% relative to sw1
.method private hidebysig static
int32 BoolToInt (
bool b
) cil managed noinlining
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldc.i4.0
IL_0002: cgt.un
IL_0004: ret
}
test cl,cl
setne al
movzx eax,al
ret
[StructLayout(LayoutKind.Explicit)]
struct BoolByte
{
[FieldOffset(0)]
public bool flag;
[FieldOffset(0)]
public byte num;
}
...
bool someBool = true;
byte num = new BoolByte() { flag = someBool }.num;