gpt4 book ai didi

c++ - 如何在 C++ 中读取复数的二进制文件

转载 作者:行者123 更新时间:2023-11-30 03:37:00 25 4
gpt4 key购买 nike

我有一个 320Mb 的二进制文件 (data.dat),包含 32e7 行十六进制数:

1312cf60 d9 ff e0 ff 05 00 f0 ff 22 00 2f 00 fe ff 33 00 |........"./...3.|
1312cf70 00 00 00 00 f4 ff 1d 00 3d 00 6d 00 53 00 db ff |........=.m.S...|
1312cf80 b7 ff b0 ff 1e 00 0c 00 67 00 d1 ff be ff f8 ff |........g.......|
1312cf90 0b 00 6b 00 38 00 f3 ff cf ff cb ff e4 ff 4b 00 |..k.8.........K.|
....

原始数字是:

(16,-144)
(-80,-64)
(-80,16)
(16,48)
(96,95)
(111,-32)
(64,-96)
(64,-16)
(31,-48)
(-96,-48)
(-32,79)
(16,48)
(-80,80)
(-48,128)
...

我有一个 matlab 代码,可以将它们读取为实数并将它们转换为复数:

nsamps = (256*1024);
for i = 1:305
nstart = 1 + (i - 1) * nsamps ;
fid = fopen('data.dat');
fseek(fid,4 * nstart ,'bof');
y = fread(fid,[2,nsamps],'short');
fclose(fid);
x = complex(y(1,:),y(2,:));

我正在使用 C++ 并尝试以 vector<complex<float>> 的形式获取数据:

std::ifstream in('data.dat', std::ios_base::in | std::ios_base::binary);
fseek(infile1, 4*nstart, SEEK_SET);
vector<complex<float> > sx;
in.read(reinterpret_cast<char*>(&sx), sizeof(int));

而且使用 C++ 获取复杂数据时非常困惑。谁能帮帮我?

最佳答案

理论

我将尝试使用您代码中的问题作为示例来解释一些要点。

让我们从代码的末尾开始。您尝试读取一个数字,该数字存储为四字节单精度 floating point number , 但你使用 sizeof(int)作为大小参数。在具有现代编译器的现代 x86 平台上 sizeof(int)趋于等于 sizeof(float) , 不能保证。 sizeof(int)依赖于编译器,所以请使用 sizeof(float)相反。

在您阅读的 matlab 代码中 2*nsamps数字,而在 C++ 代码中只读取四个字节(一个数字)。类似于 sizeof(float) * 2 * nsamps会更接近 matlab 代码。

接下来,std::complex是一个复杂的类,它(通常)可能具有任何实现定义的内部表示。但幸运的是,here我们读到

For any object z of type complex<T>, reinterpret_cast<T(&)[2]>(z)[0] is the real part of z and reinterpret_cast<T(&)[2]>(z)[1] is the imaginary part of z.

For any pointer to an element of an array of complex<T> named p and any valid array index i, reinterpret_cast<T*>(p)[2*i] is the real part of the complex number p[i], and reinterpret_cast<T*>(p)[2*i + 1] is the imaginary part of the complex number p[i].

所以我们可以投一个std::complex在那里输入字符并读取二进制数据。但是std::vector是一个类模板,它也是实现定义的内部表示!这意味着,我们不能只是 reinterpret_cast<char*>(&sx)并将二进制数据写入指针,因为它指向 vector object 的开头,这不太可能是 vector data 的开头。获取数据开头的现代 C++ 方法是调用 sx.data() . C++11 之前的方法是获取第一个元素的地址:&sx[0] .从头开始覆盖对象几乎总是会导致段错误。

好的,现在我们有了数据缓冲区的开始,它能够接收复数的二进制表示。但是当你声明 vector<complex<float> > sx; ,它的大小为零,因为你不是 pushingemplacing它是元素, vector 不会“知道”它应该调整大小。再次出现段错误。所以只需调用resize :

sx.resize(number_of_complex_numbers_to_store);

或使用适当的构造函数:

vector<complex<float> > sx(number_of_complex_numbers_to_store);

在将数据写入 vector 之前。请注意,这些方法使用存储元素数量的“高级”概念进行操作,而不是要存储的字节数。

将它们放在一起,代码的最后两行应该如下所示:

vector<complex<float> > sx(nsamps);
in.read(reinterpret_cast<char*>(sx.data()), 2 * nsamps * sizeof(float));

最小示例

如果问题仍然存在,请先尝试更简单的沙箱代码。

例如,我们写六个float s 到一个二进制文件:

std::ofstream ofs("file.dat", std::ios::binary | std::ios::out);
float foo[] = {1,2,3,4,5,6};
ofs.write(reinterpret_cast<char*>(foo), 6*sizeof(float));
ofs.close();

然后将它们读入复数 vector :

std::ifstream ifs("file.dat", std::ios::binary | std::ios::in);
std::vector<std::complex<float>> v(3);
ifs.read(reinterpret_cast<char*>(v.data()), 6*sizeof(float));
ifs.close();

最后,打印它们:

std::cout << v[0] << " " << v[1] << " " << v[2] << std::endl;

程序打印:

(1,2) (3,4) (5,6)

所以这种方法很有效。

二进制文件

这是我最初作为评论发布的关于二进制文件的评论。

二进制文件没有“行”的概念。二进制文件中“行”的数量完全取决于您在其中查看它的窗口的大小。将二进制文件想象成磁带,磁头的每个离散位置只能读取一个字节。这些字节的解释由您决定。

如果一切正常,但您得到奇怪的数字,请检查 fseek 中的位移称呼。多个字节的错误会产生随机值,而不是您希望获得的 float 。

当然,您可能只是读取 float 的 vector (或数组) s,观察上述注意事项,然后在循环中将它们转换为复数。此外,这是调试 fseek 的好方法。打电话确保您从正确的地方开始阅读。

关于c++ - 如何在 C++ 中读取复数的二进制文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40392644/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com