我在python中创建了一个名为random_from_python_int.dat的5 * 7整数矩阵二进制文件,然后我从C读取这个二进制文件。不知怎的,我无法得到正确的数字 这是我生成这个矩阵的python代码:
import numpy as np
np.random.seed(10)
filename = "random_from_python_int.dat"
fileobj = open(filename, mode='wb')
b = np.random.randint(100, size=(5,7))
b.tofile(fileobj)
fileobj.close
这将生成一个矩阵
[ [ 9 15 64 28 89 93 29]
[ 8 73 0 40 36 16 11]
[ 54 88 62 33 72 78 49]
[ 51 54 77 69 13 25 13]
[ 92 86 30 30 89 12 65] ]
但是当我从下面的C代码中读到它时:
#include <stdio.h>
#include <math.h>
int main()
{
/* later changed 'double' to 'int', but that still had issues */
double randn[5][7];
char buff[256];
FILE *latfile;
sprintf(buff,"%s","random_from_python_int.dat");
latfile=fopen(buff,"r");
fread(&(randn[0][0]),sizeof(int),35,latfile);
fclose(latfile);
printf("\n %d %d %d %d %d %d %d",randn[0][0],randn[0][1],randn[0][2],randn[0][3],randn[0][4],randn[0][5],randn[0][6]);
printf("\n %d %d %d %d %d %d %d",randn[1][0],randn[1][1],randn[1][2],randn[1][3],randn[1][4],randn[1][5],randn[1][6]);
printf("\n %d %d %d %d %d %d %d",randn[2][0],randn[2][1],randn[2][2],randn[2][3],randn[2][4],randn[2][5],randn[2][6]);
printf("\n %d %d %d %d %d %d %d",randn[3][0],randn[3][1],randn[3][2],randn[3][3],randn[3][4],randn[3][5],randn[3][6]);
printf("\n %d %d %d %d %d %d %d\n",randn[4][0],randn[4][1],randn[4][2],randn[4][3],randn[4][4],randn[4][5],randn[4][6]);
}
它会给我(调整空格以避免在stackoverflow站点上滚动):
28 15 64 93 29 -163754450 9
40 73 0 16 11 -163754450 8
33 88 62 17 91 -163754450 54
256 0 1830354560 0 4196011 -163754450 119
4197424 4197493 1826683808 4196128 2084711472 -163754450 12
我不确定是什么问题。我试过在python中编写一个浮点矩阵并在C中读取它为double,它工作正常。但是这个整数矩阵不起作用。
答案 0 :(得分:4)
正如@tdube所写,您的问题的快速摘要是:您的numpy
实现写入64位整数,而您的C代码读取32位整数。
至于更多细节,请继续阅读。
当您将整数作为二进制补码写入和读取时,您需要确保以下三个整数属性对于二进制数据的生产者和使用者都是相同的:整数大小,整数字节顺序,整数签名。
numpy和C的签名 已签名,所以我们在这里匹配。
endianness 不是问题,因为numpy和C程序都在同一台机器上,因此你可能有相同的字节序(无论它实际上是什么字节序)。
但是,尺寸是个问题。
默认情况下,numpy.random.randint
使用np.int
作为其dtype
。文档中np.int
的大小未知,但系统上的结果为64位。
numpy scalars reference列出了几种整数类型(非常不包括np.int
),其中三种组合对于与numpy
以外的程序进行稳健接口非常有用:
# | numpy | C
---+----------+---------
1 | np.int32 | int32_t
2 | np.int64 | int64_t
3 | np.intc | int
如果您恰好将基于numpy
的软件与用于构建numpy
的相同C环境相连接,请使用(np.intc
,int
)对类型(来自案例3
)看起来很安全。
但是,出于以下原因,我非常喜欢其中一种明确大小的类型(案例1
和2
):
numpy
和C中的整数大小是绝对明显的。
因此,您可以使用numpy
生成的输出连接到使用不同C环境编译的程序,该环境可能具有不同的大小int
。
您甚至可以使用numpy
生成的输出连接到用完全不同的语言编写的程序,或者在完全不同的机器上编译和运行。但是,您必须考虑不同机器方案的字节顺序。
答案 1 :(得分:3)
您的Python程序输出64位整数,而不是您尝试使用C程序读取的32位整数。
您可以更改以下代码行:
b = np.random.randint(100, size=(5,7), dtype=np.int32)
现在您将在输出文件中看到32位整数。
您的Python代码根据以下对输出文件hexdump
的分析转储64位整数。当然,您可以使用任何十六进制编辑器应用程序检查二进制数据文件。
$ hexdump random_from_python_int.dat
0000000 09 00 00 00 00 00 00 00 0f 00 00 00 00 00 00 00
0000010 40 00 00 00 00 00 00 00 1c 00 00 00 00 00 00 00
0000020 59 00 00 00 00 00 00 00 5d 00 00 00 00 00 00 00
正如@ndim在他的回答中所指出的,两个补码整数表示由三个主要元素组成:[存储] 大小, endianness < / em>和签名。我不会重复他在答案中提供的信息,只是为了说明如何推断上述输出中的信息,这是我在原始答案中开始做的事情。
对于多维数组,您可能还需要知道线性存储中order个元素。
由于您从100
间接指定(十进制)np.random.randint()
的最大非包含性随机值,因此您的值将位于小数范围[0, 100)
或[0x0, 0x64)
中在十六进制中,它们都可以用单个&#34;十六进制字节表示&#34;。请注意,上述00
输出中的非hexdump
十六进制字节均不在此范围内。如您所见,总共有8个字节用于表示每个整数值(1个非00
- 字节和7个00
- 在这种情况下基于数字范围的字节数。)< / p>
此外,您现在还可以推导出整数表示的 endianness ,在这种情况下, little endian 为 {{3} } (LSB)是线性存储中第一个字节的一部分。 LSB也可以称为最不重要的字节。
在这种情况下,您无法推断出签名,因为您的抽样中没有负值。如果您这样做,则在两个补码表示中,您会看到已签名位的值为1
。我不会深入研究两个补码负整数表示的细节,这对于这个问题来说是偏离主题的。
从文件偏移量(0x
)0000000
开始检查上面输出中的前两个8字节小端整数(和未标记的0000008
)是十六进制的值0x00000000 00000009
和0x00000000 0000000f
,分别是9
和15
的十进制值。小数值9
将是 least significant bit 或列主要订单中的第一个值,但线性存储中的第二个小数值为{ {1}}表示行主要排序,因为行元素位于连续存储中。
位于文件偏移量(15
)0x
的第三个整数值的十六进制值为0000010
,十进制值为数值0x00000000 00000040
。此值是行主要订单中预期输出中的第三个值。
为了完整性,列主要顺序将输出64
的十进制值作为线性存储中表示的第二个整数。
使代码转储32位数字,这是8
的常见实现长度(但它是&#34;实现定义&#34;在C标准中,它仅指定{的最小范围{1}}代表),您可以更改以下代码行:
int
现在您将在输出文件中看到32位整数。
int
注意:C b = np.random.randint(100, size=(5,7), dtype=np.int32)
变量的实际存储大小(精度)是&#34;实现定义&#34;,这意味着您可能需要在输出之前调整$ hexdump random_from_python_int.dat
0000000 09 00 00 00 0f 00 00 00 40 00 00 00 1c 00 00 00
0000010 59 00 00 00 5d 00 00 00 1d 00 00 00 08 00 00 00
0000020 49 00 00 00 00 00 00 00 28 00 00 00 24 00 00 00
数组整数存储大小与C的最大兼容性。请参阅@ ndim的优秀答案,提供有关此内容的更多详细信息。
必须更新您的C代码以反映二维数组的数据类型的变化。在您的代码中,int
应为numpy
。您也可以将类型double randn[5][7]
指定为@ndim,但您的编译器可能会发出错误并建议数据类型int randn[5][7]
(对于int32_t
来说是__int32_t
我的系统)。完成更改和编译后,我得到以下输出:
typedef
下面的Per @ ndim评论,您也可以使用int
,如下所示。 除非您针对整数表示的特定存储大小,否则此选项可能是最佳选项。
9 15 64 28 89 93 29
8 73 0 40 36 16 11
54 88 62 33 72 78 49
51 54 77 69 13 25 13
92 86 30 30 89 12 65
我对此进行了测试,它也产生了32位整数。
我完全同意@ndim指定整数大小最适合最大化兼容性。 Python的成语&#34;最少惊喜&#34;适用于此。