Mar*_*dik 1 c++ floating-point serialization qt gcc
我试图解决相对简单的问题,即能够将double写入文件然后再次将文件读入double.基于这个答案,我决定使用人类可读的格式.
根据这个问题,我成功地规避了一些编译器对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;
}
Run Code Online (Sandbox Code Playgroud)
在我的机器上,结果是:
serialized: 9.2263152681638151025201733115952403273156653201666065e-318
terminate called after throwing an instance of 'std::out_of_range'
what(): stod
The program has unexpectedly finished.
Run Code Online (Sandbox Code Playgroud)
也就是说,该数字太接近零而无法正确解析.起初我认为问题是这个数字是非正规的,但似乎并非如此,因为尾数以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;
}
Run Code Online (Sandbox Code Playgroud)
输出:
serialized: 9.2263152681638151025201733115952403273156653201666065e-318
de-serialized: 9.2263152681638151025201733115952403273156653201666065e-318
ok
Run Code Online (Sandbox Code Playgroud)
摘要:
回答问题#2:
这可能是我的"C-way"类型的思考,但你可以将其复制double到uint64_t(mem-copying,而不是类型转换),序列化uint64_t而不是反序列化.
这是一个例子(甚至不需要复制double到uint64_t反之亦然):
uint64_t* pi = (uint64_t*)&small;
stringstream stream;
stream.precision(maxPrecision);
stream << *pi;
cout << "serialized: " << stream.str() << endl;
uint64_t out = stoull(stream.str());
double* pf = (double*)&out;
cout << "de-serialized: " << *pf << endl;
Run Code Online (Sandbox Code Playgroud)
请注意,为了避免打破严格走样规则,你其实需要先复制它,因为标准没有规定的分配double,并uint64_t以相同的地址,比对:
uint64_t ismall;
memcpy((void*)&ismall,(void*)&small,sizeof(small));
stringstream stream;
stream.precision(maxPrecision);
stream << ismall;
cout << "serialized: " << stream.str() << endl;
ismall = stoull(stream.str());
double fsmall;
memcpy((void*)&fsmall,(void*)&ismall,sizeof(small));
cout << "de-serialized: " << fsmall << endl;
Run Code Online (Sandbox Code Playgroud)