从二进制文件读取并转换为双精度文件?
Reading from binary file and converting to double?
我正在尝试编写一个 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 个单词。
主要问题似乎是您的 temp
数组对于您的 printf 格式和数据来说不够大。 IEEE-754 double
s 的十进制指数范围从 -308 到 +308。您正在使用 "%f"
格式打印双打,这会产生一个简单的十进制表示形式。由于未指定精度,因此应用默认精度 6。这可能需要多达 1(符号)+ 309(数字)+ 1(小数点)+ 6(尾随小数位)+ 1(终止符)字符(总共 318),但你只有 space 100.
您使用 snprintf()
打印到您的缓冲区,因此不会超出那里的数组边界,但是 snprintf()
returns 将拥有的字节数被要求 ,减去终结者所需的那个。那是您 write()
的字节数,并且在许多情况下 确实 超出了您的缓冲区。您会在输出中看到结果。
其次,您还会在输出中看到大量 0.00000
,这是由于将小数字四舍五入到 6-decimal-digit 精度而产生的。
如果您更改打印数字的格式,您可能会取得更大的成功。例如,"%.16e "
将为您提供指数格式的输出,共有 17 位有效数字(小数点前一位)。这不需要内存或磁盘上过多的 space,并且它会准确地传达所有数字,无论比例如何,再次假设您的 double
是按照 IEEE 754 表示的。如果您愿意,您可以此外,通过采用@chux 在评论中建议的变体,进一步消除了 IEEE 754 格式的(相当安全的)假设。那将是最安全的方法。
还有一件事:IEEE 浮点数支持无穷大和多个 not-a-number 值。与普通的 FP 数字相比,这些数字非常少,但您仍然有可能偶尔会碰到其中一个。它们可能会很好地转换为输出,但您可能需要考虑是否需要专门处理它们。
我正在尝试编写一个 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 个单词。
主要问题似乎是您的 temp
数组对于您的 printf 格式和数据来说不够大。 IEEE-754 double
s 的十进制指数范围从 -308 到 +308。您正在使用 "%f"
格式打印双打,这会产生一个简单的十进制表示形式。由于未指定精度,因此应用默认精度 6。这可能需要多达 1(符号)+ 309(数字)+ 1(小数点)+ 6(尾随小数位)+ 1(终止符)字符(总共 318),但你只有 space 100.
您使用 snprintf()
打印到您的缓冲区,因此不会超出那里的数组边界,但是 snprintf()
returns 将拥有的字节数被要求 ,减去终结者所需的那个。那是您 write()
的字节数,并且在许多情况下 确实 超出了您的缓冲区。您会在输出中看到结果。
其次,您还会在输出中看到大量 0.00000
,这是由于将小数字四舍五入到 6-decimal-digit 精度而产生的。
如果您更改打印数字的格式,您可能会取得更大的成功。例如,"%.16e "
将为您提供指数格式的输出,共有 17 位有效数字(小数点前一位)。这不需要内存或磁盘上过多的 space,并且它会准确地传达所有数字,无论比例如何,再次假设您的 double
是按照 IEEE 754 表示的。如果您愿意,您可以此外,通过采用@chux 在评论中建议的变体,进一步消除了 IEEE 754 格式的(相当安全的)假设。那将是最安全的方法。
还有一件事:IEEE 浮点数支持无穷大和多个 not-a-number 值。与普通的 FP 数字相比,这些数字非常少,但您仍然有可能偶尔会碰到其中一个。它们可能会很好地转换为输出,但您可能需要考虑是否需要专门处理它们。