我正在尝试解决相对简单的问题,即能够将双重写入文件,然后再再次将文件读入双重。基于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
要点:
答案 0 :(得分:5)
回答问题#2:
这可能是我的“C-way”思维方式,但您可以将double
复制到uint64_t
(mem-copying,而不是类型转换),序列化{{1}相反,在反序列化时做相反的事情。
以下是一个示例(甚至无需从uint64_t
复制到double
,反之亦然):
uint64_t
请注意,为了避免中断strict-aliasing rule,您实际上需要先复制它,因为标准不会将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;
和double
分配到同一地址-alignment:
uint64_t
答案 1 :(得分:1)
如果您对其他录制方法持开放态度,可以使用frexp
:
#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);
int exp;
double x = frexp(small, &exp);
//std::cout << x << " * 2 ^ " << exp << std::endl;
stream << x << " * 2 ^ " << exp;
int outexp;
double outx;
stream.seekg(0);
stream >> outx;
stream.ignore(7); // >> " * 2 ^ "
stream >> outexp;
//std::cout << outx << " * 2 ^ " << outexp << std::endl;
std::cout << small << std::endl << outx * pow(2, outexp) << std::endl;
return 0;
}