[英]Convert amount (int) to BCD
I need to convert an Int left padded 6 bytes (amount) to a BCD in Python. 我需要将Int左填充的6个字节(数量)转换为Python中的BCD。
int = 145
expect = "\x00\x00\x00\x00\x01\x45"
The closest I come is with this code (but it needs to loop in byte pair): 我最接近的是此代码(但需要在字节对中循环):
def TO_BCD(value):
return chr((((value / 10) << 4) & 0xF0) + ((value % 10) & 0x0F))
int = 145
TO_BCD(int) # => "\x00\x00\x00\x00\x01\x45" (expected)
Here's an example. 这是一个例子。
script0.py : script0.py :
#!/usr/bin/env python3
import sys
def bcd(value, length=0, pad='\x00'):
ret = ""
while value:
value, ls4b = divmod(value, 10)
value, ms4b = divmod(value, 10)
ret = chr((ms4b << 4) + ls4b) + ret
return pad * (length - len(ret)) + ret
def bcd_str(value, length=0, pad='\x00'):
value_str = str(value)
value_str = ("0" if len(value_str) % 2 else "") + value_str
ret = ""
for i in range(0, len(value_str), 2):
ms4b = ord(value_str[i]) - 0x30
ls4b = ord(value_str[i + 1]) - 0x30
ret += chr((ms4b << 4) + ls4b)
return pad * (length - len(ret)) + ret
def main():
values = [
145,
5,
123456,
]
for value in values:
print("{0:d} - [{1:s}] - [{2:s}]".format(value, repr(bcd(value, length=6)), repr(bcd_str(value, length=6))))
# Bonus
speed_test = 1
if speed_test:
import timeit # Anti pattern: only import at the beginning of the file
print("\nTesting speed:")
stmt = "bcd({0:d})".format(1234567890 ** 32)
count = 100000
for func_name in ["bcd", "bcd_str"]:
print(" {0:s}: {1:.03f} secs".format(func_name, timeit.timeit(stmt, setup="from __main__ import {0:s} as bcd".format(func_name), number=count)))
if __name__ == "__main__":
print("Python {0:s} {1:d}bit on {2:s}\n".format(" ".join(item.strip() for item in sys.version.split("\n")), 64 if sys.maxsize > 0x100000000 else 32, sys.platform))
main()
print("\nDone.")
Output : 输出 :
[cfati@CFATI-5510-0:e:\\Work\\Dev\\StackOverflow\\q057476837]> "e:\\Work\\Dev\\VEnvs\\py_064_03.07.03_test0\\Scripts\\python.exe" script0.py Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 22:22:05) [MSC v.1916 64 bit (AMD64)] 64bit on win32 145 - ['\\x00\\x00\\x00\\x00\\x01E'] - ['\\x00\\x00\\x00\\x00\\x01E'] 5 - ['\\x00\\x00\\x00\\x00\\x00\\x05'] - ['\\x00\\x00\\x00\\x00\\x00\\x05'] 123456 - ['\\x00\\x00\\x00\\x124V'] - ['\\x00\\x00\\x00\\x124V'] Testing speed: bcd: 17.107 secs bcd_str: 8.021 secs Done.
Notes : 注意事项 :
There are 2 implementations: 有2种实现:
The speed test (at the end of main ) yields surprising results: the 2 nd (string) variant is faster (by a factor of ~2 ). 速度测试(位于main的末尾)产生了令人惊讶的结果: 第二个 (字符串)变体更快 ( 约2倍)。 A brief explanation would be that (in Python ,) modulo operation is expensive (slow) on large numbers.
一个简短的解释是(在Python中), 模运算在大量上是昂贵的(缓慢的)。
This seems fairly simple, and gets the answer you were looking for. 这似乎很简单,并且可以找到您想要的答案。 Just isolate each pair of digits and convert to ASCII.
只需隔离每对数字并转换为ASCII。
If I were doing this in high volume then I'd probably build a table (perhaps in numpy) of all the possible 100 values per byte and index it with each pair of digits in the input. 如果我要大量执行此操作,则可能会构建一个表(每个字节可能包含100个值)(也许以numpy表示),并用输入中的每对数字对其进行索引。
m = 145
print(''.join(f"\\x{m // 10**i % 10}{m // 10**(i-1) % 10}" for i in range(11, -1, -2)))
Output, although it's just a string, not any internal BCD representation 输出,尽管只是一个字符串,而不是任何内部BCD表示形式
\x00\x00\x00\x00\x01\x45
Along the same lines, you can pack the BCD into a byte string. 同样,您可以将BCD打包为一个字节字符串。 When printed, Python will interpret BCD
45
as a capital E
打印后,Python会将BCD
45
解释为大写E
import struct
m = 145
packed = struct.pack('6B', *[(m // 10**i % 10 << 4) + (m // 10**(i-1) % 10) for i in range(11, -1, -2)])
print(packed)
print(''.join(f"\\{p:02x}" for p in packed))
Output 输出量
b'\x00\x00\x00\x00\x01E'
\00\00\00\00\01\45
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.