【发布时间】:2014-11-26 12:27:42
【问题描述】:
我正在尝试解决相对简单的问题,即能够将双精度写入文件,然后再次将文件读入双精度。基于this answer,我决定使用人类可读的格式。
根据this question,我已经成功地绕过了一些编译器在 nan 和 [-]infinity 方面遇到的问题。对于有限数字,我使用std::stod 函数将数字的字符串表示形式转换为数字本身。但有时解析会因数字接近零而失败,例如在以下示例中:
#include <cmath>
#include <iostream>
#include <sstream>
#include <limits>
const std::size_t maxPrecision = std::numeric_limits<double>::digits;
const double small = std::exp(-730.0);
int main()
{
std::stringstream stream;
stream.precision(maxPrecision);
stream << small;
std::cout << "serialized: " << stream.str() << std::endl;
double out = std::stod(stream.str());
std::cout << "de-serialized: " << out << std::endl;
return 0;
}
在我的机器上结果是:
serialized: 9.2263152681638151025201733115952403273156653201666065e-318
terminate called after throwing an instance of 'std::out_of_range'
what(): stod
The program has unexpectedly finished.
也就是说,数字太接近于零而无法正确解析。起初我认为问题在于这个数字是denormal,但似乎并非如此,因为尾数以 9 而不是 0 开头。
另一方面,Qt 对这个数字没有任何问题:
#include <cmath>
#include <limits>
#include <QString>
#include <QTextStream>
const std::size_t maxPrecision = std::numeric_limits<double>::digits;
const double small = std::exp(-730.0);
int main()
{
QString string = QString::number(small, 'g', maxPrecision);
QTextStream stream(stdout);
stream.setRealNumberPrecision(maxPrecision);
stream << "serialized: " << string << '\n';
bool ok;
double out = string.toDouble(&ok);
stream << "de-serialized: " << out << '\n' << (ok?"ok":"not ok") << '\n';
return 0;
}
输出:
serialized: 9.2263152681638151025201733115952403273156653201666065e-318
de-serialized: 9.2263152681638151025201733115952403273156653201666065e-318
ok
总结:
- 这是标准库的 gcc 实现中的错误吗?
- 我可以优雅地绕过这个吗?
- 我应该只使用 Qt 吗?
【问题讨论】:
-
十六进制格式用于往返转换。上次我检查(去年?)时,g++ 和 msvc 在支持上都有点不足。但哄着他们合作并不难。
-
回答问题 #2:这可能是我的“C-way”思维方式,但您可以将
double复制到uint64(内存复制,而不是类型转换),序列化uint64,然后在反序列化时执行相反的操作。 -
@barakmanos 谢谢!但这与使用二进制格式不一样吗?我更喜欢使用人类可读的。
-
您会将其序列化为不同的(但可读的)值。顺便说一句,在实现方面,也许您应该将其序列化为
unsigned char值的数组,以避免违反严格的别名规则。 -
@MartinDrozdik:可能。在这个功能附近的某个地方有一大堆错误。我发布了一个新问题,stackoverflow.com/questions/27161720/…
标签: c++ qt gcc serialization floating-point