从 fortran 返回四精度变量
Returning a quad precision variable from fortran
所以我正在尝试 return 来自 Fortran 的四倍精度(128 位)值并在 python 中对其进行操作。但是我得到的 return 值似乎与我的预期不符。
Fortran 代码:
module testquad
implicit none
integer, parameter :: qp = selected_real_kind(p=30)
contains
real(qp) function func_quad()
real(qp) :: x
x = 5_qp
write(*,*) x,sizeof(x)
write(*,'(B128)') x
func_quad = x
end function func_quad
end module testquad
编译:
gfortran -fpic -shared -fdump-tree-all -o libtestquad.so testQuad.f90
Python 方面我使用 c_ubyte*16 数组来保存 return 值(因为 ctypes 不公开 128 位四元组类型)
import ctypes
lib = ctypes.CDLL('./libtestquad.so')
f = getattr(lib, '__testquad_MOD_func_quad')
f.argtypes = []
f.restype = ctypes.c_ubyte*16
result = f()
bb=[]
for i in bytearray(result)[::-1]:
bb.append(bin(i)[2:].rjust(8,'0'))
bb=''.join(bb)
print(bb)
运行调用fortran函数输出的代码是:
5.00000000000000000000000000000000000 16
1000000000000010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
所以我们得到 5,我们看到大小是 16(所以我得到一个四边形数字)
gfortran 似乎跳过了为符号位打印第一个 0/1。但是我们可以看到它有3个1,其余的位模式都是0。
在四边形的 wikipedia page 之后我们有
sign = 0 (gfortran misses this)
exponent = 100000000000001
significand = 0100....
转换出来:
a = 2**(int('100000000000001',base=2)-16383) # 4
b = 1 + 0/2**1 + 1/2**2 + 0/2**3 .... # 1.25
print(a * b)
5
因此,正如预期的那样,gfortran 为数字 5 打印了正确的位模式。
然而,打印出 python 中的位模式作为结果:
00000000000000000111111110110001001111101010010111111001001010000000000000000000000000000000000000000000000000000000000000000000
这明显不同。
我打印位模式时搞砸了吗?
gfortran returns a __float128 的方式有什么特别之处吗?这意味着我不能只将它解释为 16 个字节?
ctypes 如何处理 returning 一个 c_bytes 的数组有什么特别之处吗?
还有别的吗?
额外内容:
使用 -fdump-tree-all 并查看我们看到的 .original 文件:
func_quad ()
{
real(kind=16) x;
real(kind=16) __result_func_quad;
x = 5.0e+0;
// snip write statement code
__result_func_quad = x;
return __result_func_quad;
}
所以似乎没有任何事情发生 "special",变量没有被分配给 structs/pointers/arrays 来处理四边形类型。
看来我 运行 喜欢这个 答案。这指出您不能将字节数组用于浮点数,因为它没有存储在正常的 %eax 寄存器中。
所以我正在尝试 return 来自 Fortran 的四倍精度(128 位)值并在 python 中对其进行操作。但是我得到的 return 值似乎与我的预期不符。
Fortran 代码:
module testquad
implicit none
integer, parameter :: qp = selected_real_kind(p=30)
contains
real(qp) function func_quad()
real(qp) :: x
x = 5_qp
write(*,*) x,sizeof(x)
write(*,'(B128)') x
func_quad = x
end function func_quad
end module testquad
编译:
gfortran -fpic -shared -fdump-tree-all -o libtestquad.so testQuad.f90
Python 方面我使用 c_ubyte*16 数组来保存 return 值(因为 ctypes 不公开 128 位四元组类型)
import ctypes
lib = ctypes.CDLL('./libtestquad.so')
f = getattr(lib, '__testquad_MOD_func_quad')
f.argtypes = []
f.restype = ctypes.c_ubyte*16
result = f()
bb=[]
for i in bytearray(result)[::-1]:
bb.append(bin(i)[2:].rjust(8,'0'))
bb=''.join(bb)
print(bb)
运行调用fortran函数输出的代码是:
5.00000000000000000000000000000000000 16
1000000000000010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
所以我们得到 5,我们看到大小是 16(所以我得到一个四边形数字)
gfortran 似乎跳过了为符号位打印第一个 0/1。但是我们可以看到它有3个1,其余的位模式都是0。
在四边形的 wikipedia page 之后我们有
sign = 0 (gfortran misses this)
exponent = 100000000000001
significand = 0100....
转换出来:
a = 2**(int('100000000000001',base=2)-16383) # 4
b = 1 + 0/2**1 + 1/2**2 + 0/2**3 .... # 1.25
print(a * b)
5
因此,正如预期的那样,gfortran 为数字 5 打印了正确的位模式。
然而,打印出 python 中的位模式作为结果:
00000000000000000111111110110001001111101010010111111001001010000000000000000000000000000000000000000000000000000000000000000000
这明显不同。
我打印位模式时搞砸了吗?
gfortran returns a __float128 的方式有什么特别之处吗?这意味着我不能只将它解释为 16 个字节?
ctypes 如何处理 returning 一个 c_bytes 的数组有什么特别之处吗?
还有别的吗?
额外内容:
使用 -fdump-tree-all 并查看我们看到的 .original 文件:
func_quad ()
{
real(kind=16) x;
real(kind=16) __result_func_quad;
x = 5.0e+0;
// snip write statement code
__result_func_quad = x;
return __result_func_quad;
}
所以似乎没有任何事情发生 "special",变量没有被分配给 structs/pointers/arrays 来处理四边形类型。
看来我 运行 喜欢这个 答案。这指出您不能将字节数组用于浮点数,因为它没有存储在正常的 %eax 寄存器中。