C - 浮点数的序列化(浮点数、双精度数)
如何将浮点数转换为字节序列以便可以持久保存在文件中?这种算法必须快速且高度可移植。它还必须允许相反的操作,即反序列化。如果每个值只需要非常少量的多余位(持久空间),那就太好了。
How to convert a floating point number into a sequence of bytes so that it can be persisted in a file? Such algorithm must be fast and highly portable. It must allow also the opposite operation, deserialization. It would be nice if only very tiny excess of bits per value (persistent space) is required.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
假设您使用主流编译器,C 和 C++ 中的浮点值遵循 IEEE 标准,并且以二进制形式写入文件时可以在任何其他平台中恢复,前提是您使用相同的字节字节序进行写入和读取。所以我的建议是:选择一个字节顺序,在写入之前或读取之后,检查该字节顺序是否与当前平台相同;如果不是,则交换字节。
Assuming you're using mainstream compilers, floating point values in C and C++ obey the IEEE standard and when written in binary form to a file can be recovered in any other platform, provided that you write and read using the same byte endianess. So my suggestion is: pick an endianess of choice, and before writing or after reading, check if that endianess is the same as in the current platform; if not, just swap the bytes.
这可能会给您一个良好的开始 - 它将浮点值打包到
int
和long long
对中,然后您可以以通常的方式对其进行序列化。This might give you a good start - it packs a floating point value into an
int
andlong long
pair, which you can then serialise in the usual way.您始终可以按固定字节顺序(小端或大端)转换为 IEEE-754 格式。对于大多数机器来说,这要么不需要任何东西,要么需要简单的字节交换来序列化和反序列化。本身不支持 IEEE-754 的机器需要编写一个转换器,但可以使用
ldexp
和frexp
(标准 C 库函数)和位改组并不是太难。You could always convert to IEEE-754 format in a fixed byte order (either little endian or big endian). For most machines, that would require either nothing at all or a simple byte swap to serialize and deserialize. A machine that doesn't support IEEE-754 natively will need a converter written, but doing that with
ldexp
andfrexp
(standard C library functions)and bit shuffling is not too tough.你说的“便携式”是什么意思?
为了可移植性,请记住将数字保持在标准中定义的限制内:使用这些限制之外的单个数字,所有可移植性都会付之东流。
5.2.4.2.2 浮点类型的特征
请注意所有这些子句中的实现定义。
What do you mean, "portable"?
For portability, remember to keep the numbers within the limits defined in the Standard: use a single number outside these limits, and there goes all portability down the drain.
5.2.4.2.2 Characteristics of floating types <float.h>
Note the implementation-defined in all these clauses.
转换为 ascii 表示是最简单的,但如果您需要处理大量浮点数,那么您当然应该使用二进制。但如果您关心可移植性,这可能是一个棘手的问题。浮点数在不同的机器上有不同的表示方式。
如果您不想使用固定库,那么您的浮点二进制序列化器/反序列化器只需对每个位的落地位置及其代表的内容有“合同”。
这里有一个有趣的网站可以帮助您解决此问题:链接。
Converting to an ascii representation would be the simplest, but if you need to deal with a colossal number of floats, then of course you should go binary. But this can be a tricky issue if you care about portability. Floating point numbers are represented differently in different machines.
If you don't want to use a canned library, then your float-binary serializer/deserializer will simply have to have "a contract" on where each bit lands and what it represents.
Here's a fun website to help with that: link.
sprintf、fprintf ?没有比这更便携的了。
sprintf, fprintf ? you don't get any more portable than that.
您需要什么级别的便携性?如果要在具有与生成该文件相同的操作系统的计算机上读取该文件,那么使用二进制文件并仅保存和恢复位模式应该可行。否则正如 boytheo 所说,ASCII 是你的朋友。
What level of portability do you require? If the file is to be read on a computer with the same OS that it was generated on, than you using a binary file and just saving and restoring the bit pattern should work. Otherwise as boytheo said, ASCII is your friend.
此版本中每个浮点值仅多出一个字节来指示字节顺序。但我认为,它仍然不太便携。
This version has excess of only one byte per one floating point value to indicate the endianness. But I think, it is still not very portable however.
开始了。
便携式 IEEE 754 序列化/反序列化
无论机器的内部浮点如何工作
表示。
https://github.com/MalcolmMcLean/ieee754
Here we go.
Portable IEEE 754 serialisation / deserialisation that should
work regardless of the machine's internal floating point
representation.
https://github.com/MalcolmMcLean/ieee754
fwrite()、fread()?您可能需要二进制文件,并且不能将字节打包得更紧,除非您想牺牲在程序中执行的精度,然后无论如何 fwrite() fread() ;浮动一个;双b; a=(浮点数)b; fwrite(&a,1,sizeof(a),fp);
如果您携带不同的浮点格式,它们可能不会以直接二进制的方式进行转换,因此您可能必须将这些位分开并执行数学运算,这是乘以该乘方,等等。 IEEE 754 是一个可怕的标准使用但广泛,因此可以最大限度地减少工作量。
fwrite(), fread()? You will likely want binary, and you cannot pack the bytes any tighter unless you want to sacrifice precision which you would do in the program and then fwrite() fread() anyway; float a; double b; a=(float)b; fwrite(&a,1,sizeof(a),fp);
If you are carrying different floating point formats around they may not convert in a straight binary sense, so you may have to pick apart the bits and perform the math, this to the power that plus this, etc. IEEE 754 is a dreadful standard to use but widespread so it would minimize the effort.