从二进制文件中读取并转换为双精度?
Posted
技术标签:
【中文标题】从二进制文件中读取并转换为双精度?【英文标题】:Reading from binary file and converting to double? 【发布时间】:2017-02-03 18:26:23 【问题描述】:我正在尝试编写一个读取二进制文件并将其转换为数据类型的 C 程序。我正在生成一个带有 head 命令head -c 40000 /dev/urandom > data40.bin
的二进制文件。该程序适用于数据类型 int 和 char,但适用于 double。这是程序的代码。
void double_funct(int readFrom, int writeTo)
double buffer[150];
int a = read(readFrom,buffer,sizeof(double));
while(a!=0)
int size = 1;
int c=0;
for(c=0;c<size;c++)
char temp[100];
int x = snprintf(temp,100,"%f ", buffer[c]);
write(writeTo, temp, x);
a = read(readFrom,buffer,sizeof(double));
这是有效的 char 函数
void char_funct(int readFrom, int writeTo)
char buffer[150];
int a = read(readFrom,buffer,sizeof(char));
while(a!=0)
int size = 1;
int c=0;
for(c=0;c<size;c++)
char temp[100]=" ";
snprintf(temp,100,"%d ", buffer[c]);
write(writeTo, temp, strlen(temp));
a = read(readFrom,buffer,sizeof(char));
问题是使用 char 我需要使用 wc -w file
得到 40000 个单词,然后我得到了它们。现在使用 double 我得到随机数量的单词,但理论上我应该从 40000 字节的数据中得到 5000,但我得到 4000 到 15000 之间的随机数量,对于 char 我得到 40000,就像一个字符应该有 1 个字节一样。
我不知道有什么问题,同样的代码适用于 int
,我从 40000 个字节的数据中得到 10000 个字。
【问题讨论】:
假设read()
读取请求的全部字节数是不安全的。必须使用返回值来确定实际读取了多少字节。
此外,如果发生错误,read()
将返回 -1
。您不考虑这种可能性,如果确实发生错误,您将处理谁知道什么数据。
这一行:int x = snprintf(temp,100,"%f ", buffer[c]);
从缓冲区中取出一个字符并尝试将其转换为浮点数。您可能想要检查返回值x
,它告诉您有多少写入缓冲区。但是,这肯定不是你想要做的。
此外,write()
在传输的字节数方面与read()
具有相似的特征,但实际上这对于本地文件来说很少出现问题。
@bruceg 在该版本中,缓冲区是double
数组,而不是其他版本中的char
数组。
【参考方案1】:
主要问题似乎是您的 temp
数组对于您的 printf 格式和数据来说不够大。 IEEE-754 double
s 的十进制指数范围从 -308 到 +308。您正在使用"%f"
格式打印双打,这会产生一个简单的十进制表示。由于未指定精度,因此应用默认精度 6。这可能需要多达 1(符号)+ 309(数字)+ 1(小数点)+ 6(尾随小数位)+ 1(终止符)字符(总共 318),但您只有 100 个空间。
您使用snprintf()
打印到缓冲区,因此不会超出那里的数组边界,但snprintf()
返回需要的字节数,减去所需的字节数终结者。这就是您write()
的字节数,并且在许多情况下确实 超出了您的缓冲区。您会在输出中看到结果。
其次,您还会在输出中看到大量 0.00000
,这是因为将小数字四舍五入到 6 位小数精度。
如果您更改打印数字的格式,您可能会获得更好的成功。例如,"%.16e "
将为您提供指数格式的输出,共有 17 位有效数字(小数点前一位)。这将不需要内存或磁盘上的过多空间,并且它将准确地传达所有数字,无论规模如何,再次假设您的 double
s 是根据 IEEE 754 表示的。如果您愿意,您可以进一步消除(非常安全) 通过采用@chux 在 cmets 中建议的变体来假设 IEEE 754 格式。这将是最安全的方法。
还有一件事:IEEE 浮点支持无穷大和多个非数字值。与普通的 FP 数字相比,这些数字很少,但您仍然有可能偶尔会遇到其中一个。它们可能会很好地转换为输出,但您可能需要考虑是否需要专门处理它们。
【讨论】:
注意:关闭 1。需要buffer[318]
。 --> 1e308
为“309(数字)”。
"%.15e"
很好,但不足以将一些不同的double
打印为不同的文本。建议printf("%.*e\n", DBL_DECIMAL_DIG - 1, buffer[c]);
以不同方式打印所有不同的double
。或printf("%a\n", buffer[c]);
谢谢@chux。我已经修正了我的数学并根据你的 cmets 调整了我建议的格式。您也很正确,可以进行概括以消除有关浮点表示的假设,我很满意我的回答,请参阅您的评论以获取详细信息。以上是关于从二进制文件中读取并转换为双精度?的主要内容,如果未能解决你的问题,请参考以下文章