首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >通过文本文件往返的浮点数的校验和

通过文本文件往返的浮点数的校验和
EN

Stack Overflow用户
提问于 2013-03-15 18:11:09
回答 5查看 855关注 0票数 1

我需要将几个浮点数写到一个文本文件中,并用它们存储一个CRC32校验和。然后,当我从文本文件中读回浮点数时,我希望重新计算校验和,并将其与先前保存文件时计算的校验和进行比较。我的问题是校验和有时会失败。这是因为相等的浮点数可以由不同的位模式表示。为了完整起见,我将在接下来的段落中总结代码。

我改编了我在阅读this question后发现的this CRC32 algorithm。它看起来是这样的:

代码语言:javascript
运行
复制
uint32_t updC32(uint32_t octet, uint32_t crc) {
    return CRC32Tab[(crc ^ octet) & 0xFF] ^ (crc >> 8);
}

template <typename T>
uint32_t updateCRC32(T s, uint32_t crc) {
    const char* buf = reinterpret_cast<const char*>(&s);
    size_t len = sizeof(T);

    for (; len; --len, ++buf)
        crc = updC32(static_cast<uint32_t>(*buf), crc);
    return crc;
}

CRC32Tab包含的值与上面链接的文件中的大型数组完全相同。

这是我如何将浮点数写入文件并计算校验和的简略版本:

代码语言:javascript
运行
复制
float x, y, z;

// set them to some values

uint32_t crc = 0xFFFFFFFF;
crc = Utility::updateCRC32(x, crc);
crc = Utility::updateCRC32(y, crc);
crc = Utility::updateCRC32(z, crc);
const uint32_t actualCrc = ~crc;

// stream is a FILE pointer, and I don't mind the scientific representation
fprintf(stream, " ( %g %g %g )", x, y, z);
fprintf(stream, " CRC %u\n", actualCrc);

我从文件中读取值,如下所示。实际上涉及的内容要多得多,因为文件具有更复杂的语法并且必须进行解析,但假设getNextFloat()返回之前编写的每个浮点数的文本表示形式。

代码语言:javascript
运行
复制
float x = std::atof(getNextFloat());
float y = std::atof(getNextFloat());
float z = std::atof(getNextFloat());

uint32_t crc = 0xFFFFFFFF;
crc = Utility::updateCRC32(x, crc);
crc = Utility::updateCRC32(y, crc);
crc = Utility::updateCRC32(z, crc);
const uint32_t actualCrc = ~crc;

const uint32_t fileCrc = // read the CRC from the file
assert(fileCrc == actualCrc); // fails often, but not always

此问题来源是std::atof将返回从文件读取的字符串中编码的浮点数的位表示,而不是用于将该字符串写入文件的浮点数的位表示。

所以,我的问题是:除了对字符串本身进行校验和之外,还有其他方法可以实现通过文本表示往返传递的浮点数校验和的目标吗?

感谢您的阅读!

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2013-03-15 19:00:10

从您的评论中可以明显看出问题的来源:

如果我没有完全弄错的话,这里没有发生舍入。%g说明符选择准确表示数字的最短字符串表示形式。

这是不正确的。如果未指定精度,则默认为6,并且肯定会对大多数浮点输入进行舍入。

如果您需要一种人类可读的、可往返的格式,%a是目前为止的最佳选择。如果做不到这一点,您将需要指定至少为9的精度(假设您系统上的float是IEEE-754单精度)。

您可能仍然会被NaN编码绊倒,因为标准没有指定如何或是否必须打印它们。

票数 1
EN

Stack Overflow用户

发布于 2013-03-15 18:39:30

如果文本文件不一定是人类可读的,请改用hexadecimal float literals,因为它们是精确的,所以您不会遇到文本值和内存中的值之间存在差异的问题。

票数 1
EN

Stack Overflow用户

发布于 2013-03-15 18:45:13

如果你的标准库的浮点数到文本和文本到浮点数的转换做了适当的舍入,你只需要足够的有符号的数字就可以让float->text->float往返是无损的,除非你还有Infs和NaNs,但它仍然应该是“值保留”的,不一定是位模式保留,因为我认为无穷大或NaN有多种表示形式。对于IEEE-754,64位双17位有效数字刚好足以使往返相对于实际值无损。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15429593

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档