Python 的float
数据类型确实使用双精度(64 位)。但是,对于我的具体实现(通过OSC传输类型标记的值),我想区分可以表示为(32 位)单精度浮点数和(64 位)双精度浮点数的值。
更准确地说,我想做这样的事情:
if isdouble(value):
binary=struct.pack('>d', value)
else:
binary=struct.pack('>f', value)
有没有可行的方法来实现这一目标?
Python 的float
数据类型确实使用双精度(64 位)。但是,对于我的具体实现(通过OSC传输类型标记的值),我想区分可以表示为(32 位)单精度浮点数和(64 位)双精度浮点数的值。
更准确地说,我想做这样的事情:
if isdouble(value):
binary=struct.pack('>d', value)
else:
binary=struct.pack('>f', value)
有没有可行的方法来实现这一目标?
如果您不介意损失一点精度,您可以测试范围(请参阅Alfe 的回答):
def isdouble(value):
return not (1.18e-38 <= abs(value) <= 3.4e38)
或反转以测试单精度:
def issingle(value):
return 1.18e-38 <= abs(value) <= 3.4e38:
这些将防止引发OverflowError
异常,另一种方法是抓住它。
请注意 , float('-0')
, float('+0')
,float('inf')
和float('-inf')
将float('nan')
在这些测试中进行双重测试;如果您希望将它们存储在 4 个字节而不是 8 个字节中,请明确测试这些。
我建议使用 float 尝试它,如果失败(由于范围溢出)使用双版本:
try:
binary = struct.pack('>f', value)
except OverflowError:
binary = struct.pack('>d', value)
范围是您的问题完全有意义的唯一方面。
如果涉及精度,您的问题就失去了意义,因为正如您所说,Python总是在内部使用双精度数,甚至一个简单3.3
的 is,打包和解包为浮点数,仅在3.299999952316284
之后:
struct.unpack('>f', struct.pack('>f', 3.3))
(3.299999952316284,)
所以实际上没有双精度可以表示为浮点数。(通常没有一个不是 int 或最初从浮点数出来的。)
但是,您可以检查您的号码的打包解包版本是否等于原始版本,如果是,请使用浮动版本:
try:
binary = struct.pack('>f', value)
if struct.unpack('>f', binary)[0] != value:
binary = struct.pack('>d', value)
except OverflowError:
binary = struct.pack('>d', value)
您可以通过将浮点数转换回双精度并将结果与 x 进行比较来检查双精度 x 是否可以精确地表示为浮点数。
所有浮点数都可以精确表示为双精度,因此反向转换不涉及舍入。当且仅当浮点数等于该双精度时,结果才会等于原始双精度。
单精度
IEEE 单精度浮点标准表示需要一个 32 位字,它可以表示为从左到右从 0 到 31 的编号。
第一位是符号位 S,接下来的八位是指数位“E”,最后 23 位是小数“F”:
双精度
IEEE 双精度浮点标准表示需要一个 64 位字,可以表示为从左到右从 0 到 63 的编号。
第一位是符号位 S,接下来的 11 位是指数位“E”,最后 52 位是小数“F”: