如何在不设置第23位的情况下在python中创建自定义NaN(单精度)?
我试图通过选择分数位来创建浮点NAN。但python float在解释NaN时似乎总是设置第23个分数位(IEEE754 single) 所以,我的问题是:是否可以在python中定义一个浮点nan而不设置第23位 (我正在使用Python 2.7) IEEE 754中的NAN具有以下格式:如何在不设置第23位的情况下在python中创建自定义NaN(单精度)?,python,struct,ctypes,nan,floating-point-conversion,Python,Struct,Ctypes,Nan,Floating Point Conversion,我试图通过选择分数位来创建浮点NAN。但python float在解释NaN时似乎总是设置第23个分数位(IEEE754 single) 所以,我的问题是:是否可以在python中定义一个浮点nan而不设置第23位 (我正在使用Python 2.7) IEEE 754中的NAN具有以下格式: 符号=0或1 偏置指数=所有1位 分数=除所有0位之外的任何内容(因为所有0位表示无穷大) 因此,NaN的十六进制表示可以是0x7F800001,但是当将此int解释为浮点并将其解释回int时,会得到0x7
符号=0或1
偏置指数=所有1位
分数=除所有0位之外的任何内容(因为所有0位表示无穷大) 因此,NaN的十六进制表示可以是0x7F800001,但是当将此int解释为浮点并将其解释回int时,会得到0x7FC00001 第一次尝试:struct.pack/unpack:
import struct
def hex_to_float(value):
return struct.unpack( '@f', struct.pack( '@L', value) )[0]
def float_to_hex(value):
return struct.unpack( '@L', struct.pack( '@f', value) )[0]
print hex(float_to_hex(hex_to_float(0x7f800001)))
# 0x7fc00001
第二次尝试:ctypes
import ctypes
def float2hex(float_input):
INTP = ctypes.POINTER(ctypes.c_uint)
float_value = ctypes.c_float(float_input)
my_pointer = ctypes.cast(ctypes.addressof(float_value), INTP)
return my_pointer.contents.value
def hex2float(hex_input):
FLOATP = ctypes.POINTER(ctypes.c_float)
int_value = ctypes.c_uint(hex_input)
my_pointer = ctypes.cast(ctypes.addressof(int_value), FLOATP)
return my_pointer.contents.value
print hex(float2hex(hex2float(0x7f800001)))
# 0x7fc00001L
第三次尝试:xdrlib打包机。同样的结果。你到底想做什么 任何使用浮动的Python代码在最好的情况下都会忽略“精心编制”的NaN,在最坏的情况下会崩溃 如果要将此值传递给Python代码序列化之外的对象,或者调用C API,只需使用struct使用所需的确切字节来定义它,然后将这些字节发送到所需的目标 另外,如果您使用的是NumPy,那么,是的,您可以创建特殊的nan,并期望在一个ndarray中创建一个reatend,但是实现这一点的方法也是通过使用struct指定您想要的确切字节,并以某种方式转换数据类型,同时保留缓冲区内容 在构建80位双倍数字以与NumPy一起使用时检查此答案,以获得解决方案: (我在这里尝试了numpy.frombuffer,它将您在那里创建的字节序列解释为32位,如果您觉得合适的话:
import numpy as np
import binascii
a = "7f800001"
b = binascii.unhexlify(a) # in Python 2 a.decode("hex") would work, but not Python3
# little endian format we need to revert the byte order
c = "".join(b[::-1])
x = np.frombuffer(c, dtype="float32")
x.tobytes()
将打印原件-
'\x01\x00\x80\x7f'
检查数组x将显示它实际上是一个NaN:
>>> x
array([nan], dtype=float32)
但是,出于上述原因,如果您使用x[0]从numpy数组中提取值,它将转换为具有默认值的“巴氏消毒”浮点64 NaN。根本问题是您将C浮点(具有32位)转换为Python浮点(具有64位,即C术语中的
double
)然后回到C-float
两个cConversion的执行并不总是导致原始输入-您正在目睹这种情况
如果确切的位模式很重要,您应该不惜任何代价避免上述转换
以下是一些血淋淋的细节: 因此,当
struct.unpack('=f',一些字节)
(请注意,与您使用的本机大小('@')相比,我使用的是标准大小=
-格式字符,例如@L
在Windows和Linux上的含义不同),以下情况发生了:
- 是叫,叫什么?
- ,它将数据(或)解释为
- ,即浮动
- 但是将其转换为
(因为函数返回一个'double')double
0x7f800001
成为命令0x7FF80000000
如您所见,操作struct.unpack('=f',struct.pack('=L',value))[0]
的结果已经不是放入的结果
但是,为python floatvalue
(它是C的double
的包装)调用struct.pack(
=f,value)
),将使我们实现从double
到float
的转换,即。(将标量双精度浮点值转换为标量单精度浮点值)调用并
0x7FF80000200000
变成0x7fc00001
谢谢你的深入解释。我真的很想知道为什么会发生这种情况。谢谢。这就是我担心的。我想我将不得不忍受这种行为,而不是改变所有的底层代码来应对那个极端情况。