我希望能够在python中访问数字的符号位。我可以在C中执行n >> 31
之类的操作,因为int表示为32位。
我不能使用条件运算符和> <
答案 0 :(得分:6)
在python 3中,整数没有固定的大小,并且没有使用内部CPU表示法表示(它允许处理非常大的数字而没有麻烦)。
所以最好的方法是
signbit = 1 if n < 0 else 0
或
signbit = int(n < 0)
编辑:如果你不能使用<
或>
(这是可笑的,但也是如此)你可以使用a-b
如果a大于{{b
将为正的事实1}},所以你可以做到
abs(a-b) == a-b
不使用<
或>
(至少在文字中,因为abs
使用它,您可以信任我)
答案 1 :(得分:2)
我认为在Python中并没有真正的符号位概念。就程序员而言,int
只是具有特定行为的类型。您无法访问低级别表示。即使bin(-3)
返回“否定”二进制表示形式:'-0b11'
但是,如果两个整数没有比较,有很多方法可以获得符号或更大的符号。以下方法滥用浮点数学以避免比较。
def sign(a):
try:
return (1 - int(a / (a**2)**0.5)) // 2
except ZeroDivisionError:
return 0
def return_bigger(a, b):
s = sign(b - a)
return a * s + b * (1 - s)
assert sign(-33) == 1
assert sign(33) == 0
assert return_bigger(10, 15) == 15
assert return_bigger(25, 3) == 25
assert return_bigger(42, 42) == 42
(a**2)**0.5
可以替换为abs
但我在内部打赌这是通过比较来实现的。try
/ except
。答案 2 :(得分:2)
为什么右移符号位以产生1或0在Python中不起作用的原因是,从概念上讲,负整数的位表示用无限数 1 填充左边的位(就像非负数被视为填充有无限数量的 0 位一样)。但是操作n >> 31
确实有效(假设n
在带符号的32位数字范围内),因为它放置了符号位(或者,如果您愿意,可以使用左填充之一)位)的最低位。您只需要去除其余的左填充位,就可以使用按位操作和来完成此操作,如下所示:
n >> 31 & 1
或者您可以利用所有一位表示-1的事实,并简单地对结果求反:
-(n >> 31)
或者,除了最低的32个 1 位以外,您还可以在进行移位之前将其切掉,如下所示:
(n & 0xffffffff) >> 31
所有这些都是在假设您使用的数字适合带符号的32位int的情况下进行的。如果n
可能需要用64位表示,则移位63位而不是31位;如果它只有16位数字,则移位15位就足够了(并且,如果使用(n & 0xffffffff) >> 31
变体,请调整f
的数量)
在机器代码级别,和求和/求反和移位可能比使用比较更有效率。前者只是一些机器指令,而后者通常会简化为分支。分支不仅需要更多的机器指令,而且还会对现代CPU的流水线和乱序执行产生不良影响。 Python的执行与机器代码的执行之间存在一定距离,因此,要说出任何有关Python的性能影响的信息都比较困难。它可能取决于上下文(就像在机器代码中一样),因此通常也很难进行测试。 (注意:我对CPython或一般情况下在Python中如何执行低级执行了解不多。对于执行此操作的人,这可能并不难回答。)
如果您不知道n
有多大(在Python中,不需要整数就可以容纳任何特定位数),则可以使用bit_length()
进行查找。这将适用于任何大小的整数:
-(n >> n.bit_length())
bit_length()
操作可能会归结为一条机器指令,或者实际上可能需要一个循环来查找结果,具体取决于实现和底层机器体系结构,在后一种情况下,这应该是比使用常量要昂贵得多
最后的评论:实际上,n >> 31
不能保证像您在C语言中一样工作,因为C语言对>>
是否进行逻辑右移(例如您)没有定义假设)或算术右移(就像Python一样)。在某些语言中,例如Java,您可以使用>>>
运算符保证逻辑右移,而使用>>
保证算术右移。
答案 3 :(得分:0)
这个怎么样?
def is_negative(num, places):
return not long(num * 10**places) & 0xFFFFFFFF == long(num * 10**places)
效率不高,但未使用&lt;或者&gt;绝对限制你的怪异。请注意,零将评估为正数。