获取和设置值的特定位
Get and Set specific bits of a value
对于给定的值,我需要能够读取和写入该值的特定位。
示例:
n = 341
# bin(341) is '0b101010101'
get_bits(n, start = 2, end = 6)
# Returns 10 = '0b1010'
n = set_bits(n, start = 2, end = 6, newValue = 6)
# Replaces bits [2:6] of n with 0b0110
# Makes n = 309 = '0b100110101'
这里有三个函数可以做到这一点! (第一个包含一些常用代码):
def mask_and_shift(start, end, length):
"""Return a mask and shift value to access [<start>:<end>] of <length> bits"""
shift = length - end
mask = (1 << end - start) - 1 << shift
return mask, shift
def get_bits(n, start, end, length : int = None):
"""Read bits [<start>:<end>] of <n> and return them
<length> forces <n> into that bit length"""
mask, shift = mask_and_shift(start, end, length = n.bit_length() if length is None else length)
return (n & mask) >> shift
def set_bits(n, start, end, newValue, length : int = None):
"""Change bits [<start>:<end>] of <n> to <newValue> and return <n>
<length> forces <n> into that bit length"""
mask, shift = mask_and_shift(start, end, length = n.bit_length() if length is None else length)
return (n & ~mask) | (newValue << shift)
(请随意提出改进建议,两者的第一行都非常简陋,但我更喜欢这种语法,而不是将三元运算符分成另一行,因为这样看起来确实应该将其整理成 mask_and shift
尽管这会使 mask_and_shift
本身无用)
通常位从右到左编号。如果您使用该标准约定和开始-停止值(如范围),您的函数将更易于使用按位运算符实现:
def get_bits(n, start, end):
return (n&((1<<end)-1))>>start
def set_bits(n, start, end, value):
mask = (1<<end) - (1<<start)
return (n&~mask) | (value<<start)&mask
输出:
n = 341 # 101010101
# 876543210 bit numbers
# 101010101 = 341
f"{get_bits(n,3,7):b}" # ..1010... = 10
# 876543210
# 101010101 = 341
f"{set_bits(n,3,7,12):b}" # 101100101 = 357
# ..^^^^...
# ..1100... = 12
# 876543210
对于给定的值,我需要能够读取和写入该值的特定位。
示例:
n = 341
# bin(341) is '0b101010101'
get_bits(n, start = 2, end = 6)
# Returns 10 = '0b1010'
n = set_bits(n, start = 2, end = 6, newValue = 6)
# Replaces bits [2:6] of n with 0b0110
# Makes n = 309 = '0b100110101'
这里有三个函数可以做到这一点! (第一个包含一些常用代码):
def mask_and_shift(start, end, length):
"""Return a mask and shift value to access [<start>:<end>] of <length> bits"""
shift = length - end
mask = (1 << end - start) - 1 << shift
return mask, shift
def get_bits(n, start, end, length : int = None):
"""Read bits [<start>:<end>] of <n> and return them
<length> forces <n> into that bit length"""
mask, shift = mask_and_shift(start, end, length = n.bit_length() if length is None else length)
return (n & mask) >> shift
def set_bits(n, start, end, newValue, length : int = None):
"""Change bits [<start>:<end>] of <n> to <newValue> and return <n>
<length> forces <n> into that bit length"""
mask, shift = mask_and_shift(start, end, length = n.bit_length() if length is None else length)
return (n & ~mask) | (newValue << shift)
(请随意提出改进建议,两者的第一行都非常简陋,但我更喜欢这种语法,而不是将三元运算符分成另一行,因为这样看起来确实应该将其整理成 mask_and shift
尽管这会使 mask_and_shift
本身无用)
通常位从右到左编号。如果您使用该标准约定和开始-停止值(如范围),您的函数将更易于使用按位运算符实现:
def get_bits(n, start, end):
return (n&((1<<end)-1))>>start
def set_bits(n, start, end, value):
mask = (1<<end) - (1<<start)
return (n&~mask) | (value<<start)&mask
输出:
n = 341 # 101010101
# 876543210 bit numbers
# 101010101 = 341
f"{get_bits(n,3,7):b}" # ..1010... = 10
# 876543210
# 101010101 = 341
f"{set_bits(n,3,7,12):b}" # 101100101 = 357
# ..^^^^...
# ..1100... = 12
# 876543210