Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/343.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在不设置第23位的情况下在python中创建自定义NaN(单精度)?_Python_Struct_Ctypes_Nan_Floating Point Conversion - Fatal编程技术网

如何在不设置第23位的情况下在python中创建自定义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

我试图通过选择分数位来创建浮点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时,会得到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')
在x86-64上,最后一次转换是指操作(即,将标量单精度浮点值转换为标量双精度浮点值),此操作会导致

0x7f800001
成为命令
0x7FF80000000

如您所见,操作
struct.unpack('=f',struct.pack('=L',value))[0]
的结果已经不是放入的结果

但是,为python float
value
(它是C的
double
的包装)调用
struct.pack(
=f
,value)
),将使我们实现从
double
float
的转换,即。(将标量双精度浮点值转换为标量单精度浮点值)调用并


0x7FF80000200000
变成
0x7fc00001

谢谢你的深入解释。我真的很想知道为什么会发生这种情况。谢谢。这就是我担心的。我想我将不得不忍受这种行为,而不是改变所有的底层代码来应对那个极端情况。