如何将0/1转换为有效签名?

Cro*_*ten 3 python optimization python-3.x

看下面的函数,其中a是一个无符号字节0-255,b是一个浮点数:

def convert(a, b):
    if a & 0x80:
        return -b
    return b
Run Code Online (Sandbox Code Playgroud)

它否定b了的第一位a,但没有设置时什么也不做。可能会认为这不是很酷,因为条件语句破坏了CPU中的分支预测。因此,人们将尝试将其转换为一种计算。

但是我只找到了这种解决方案,看起来效率不高:

def convert(a, b):
    return (-1)**(a & 0x80) * b
Run Code Online (Sandbox Code Playgroud)

哪一个更有效?编译器会简化第二个吗?有没有更好的办法?

Sha*_*ger 6

这是Python。在您可能会想到的意义上,没有编译器。假设您使用的是CPython(参考解释器),那么所有内容都会通过一个巨大的switch语句循环运行,该switch语句随即读取和解释每个字节码。您对分支预测的担心在这里无关紧要;在执行的每个操作中switch,在类型检查,动态函数指针查找和调用之间,将有六个CPU级别的分支。远距离的跳转在最终读取字节码时可能会稍微损害数据缓存相距几百个字节而不是下一个字节代码,但是分支预测(或缺少分支预测)不是问题(100%可预测的跳转将具有相同的问题)。

基本上,您在此处所做的任何可能在C语言中运行并被编译器的优化器优化为理想代码的操作都将不适用于CPython。所以不要打扰。编写完整的代码,如果速度太慢则对其进行概要分析,然后努力优化“最热”(最常被调用)的部分。您正在这里进行过早的优化,应该停止。

如果我是你,我会选择#1(可能用替换if a & 0x80:if a >= 0x80:因为前者需要返回一个int,然后必须对它进行更真实的测试,而后者则bool直接返回,这对真值测试是最便宜的东西) ,因为它很简单,而且不太可能可怕;只有调查的其他选项,如果你的程序太慢,并且分析说,这个代码特定位热点。

  • 仅供参考,我确实做了局部微基准测试。当`a小于128时,选项#1和#2基本相同,但是当`a`大于或等于128时,#2慢得多(运行时间长约3倍)。 Python没有对-1 ** x进行显式优化,因此最终执行了-1和1的多次无意义乘法来计算-1 ** 128。选项1将a和0x80替换为a> = 0x80甚至更快(运行时间降低20-40%,具体取决于是否需要取反)。 (2认同)