如何在C++中精确显示和存储和使用精确到一定小数位的数据?
How to accurately display and store and use data exactly up to certain number of decimal places in C++?
如果我有一个 double
变量,我想按照四舍五入的标准规则将它的值存储在一个文件中,保留两位小数。我不只是想存储和显示最多两位小数的数据,而且我还想使用这些数据进行算术运算,当我重新打开文件时,精确到两位小数。换句话说,当我将文件中的这些数据读入 double
变量时,我希望这些数据也能准确地加载到小数点后两位,就像我存储它时一样准确。到目前为止,使用 <iomanip>
和 fixed
以及 setprecision
仅用于显示与 std::cout
一起使用的输出。不过我可能错了。请使用以下示例说明如何完成此操作?另外如何将来自 double
变量的数据存储到 binary
文件中的小数点后两位?
std::ofstream file("data.txt");
int hours = 8, mins= 35;
char ap='p';
double format_24_hr=0.00;
format_24_hr = static_cast<double>(hours) + 12.00 + static_cast<double>(mins)/60.00;
file<<format_24_hr; // how to store double to two decimal places in a binary file
file.close();
此外,当我像下面这样读取文件时,如何确保它加载的数据与我存储的数据完全一样,精确到小数点后两位?
std::ifstream file("data.txt");
double var=0.00;
file>>var; // would the data read here be exactly loaded to two decimal places as I stored it?
file.close();
您所描述的是fixed point representation. Trying to use a floating point representation for fixed point values often leads to issues, as you have discovered and as described in Is floating point math broken? See Fixed point vs Floating point number更详细的表示比较。
一种合理的(有时也很简单,取决于您的需要)方法是使用整数来表示您的值。您可以围绕这个整数构建一个界面,以便在查看时将其除以 100,使其看起来像一个小数点后有两位数的数字。也就是说,如果存储的值为 2058
,使用该值的代码将看到(最接近的 double
值)20.58
。这是一个起点的例子:
class FixedPoint {
int value;
public:
double get() const { return static_cast<double>(value) / 100.0; }
// Also define other needed functionality, including arithmetic.
// Multiplication and division require a bit of care.
};
但是您的示例代码显示尝试将小时和分钟存储为小数小时。这已经是有问题的,因为这种关联并不精确。例如,您不能从整数小时和分钟中得到 20.58
小时;你可以接近 (20.58333333...
),但不完全是。
比小数小时更一致的方法是总分钟数。而不是存储
static_cast<double>(hours) + 12.00 + static_cast<double>(mins)/60.00
到一个文件并处理精度问题,你可以通过存储
来获得完美的精度
(hours + 12) * 60 + mins
这是一个整数,回避了使用多少位小数的问题。读取保存的值时将恢复完全相同的值。
为人类可读的输出保存小数小时(如果需要),并为需要由程序存储和检索的值使用总分钟数。
如果我有一个 double
变量,我想按照四舍五入的标准规则将它的值存储在一个文件中,保留两位小数。我不只是想存储和显示最多两位小数的数据,而且我还想使用这些数据进行算术运算,当我重新打开文件时,精确到两位小数。换句话说,当我将文件中的这些数据读入 double
变量时,我希望这些数据也能准确地加载到小数点后两位,就像我存储它时一样准确。到目前为止,使用 <iomanip>
和 fixed
以及 setprecision
仅用于显示与 std::cout
一起使用的输出。不过我可能错了。请使用以下示例说明如何完成此操作?另外如何将来自 double
变量的数据存储到 binary
文件中的小数点后两位?
std::ofstream file("data.txt");
int hours = 8, mins= 35;
char ap='p';
double format_24_hr=0.00;
format_24_hr = static_cast<double>(hours) + 12.00 + static_cast<double>(mins)/60.00;
file<<format_24_hr; // how to store double to two decimal places in a binary file
file.close();
此外,当我像下面这样读取文件时,如何确保它加载的数据与我存储的数据完全一样,精确到小数点后两位?
std::ifstream file("data.txt");
double var=0.00;
file>>var; // would the data read here be exactly loaded to two decimal places as I stored it?
file.close();
您所描述的是fixed point representation. Trying to use a floating point representation for fixed point values often leads to issues, as you have discovered and as described in Is floating point math broken? See Fixed point vs Floating point number更详细的表示比较。
一种合理的(有时也很简单,取决于您的需要)方法是使用整数来表示您的值。您可以围绕这个整数构建一个界面,以便在查看时将其除以 100,使其看起来像一个小数点后有两位数的数字。也就是说,如果存储的值为 2058
,使用该值的代码将看到(最接近的 double
值)20.58
。这是一个起点的例子:
class FixedPoint {
int value;
public:
double get() const { return static_cast<double>(value) / 100.0; }
// Also define other needed functionality, including arithmetic.
// Multiplication and division require a bit of care.
};
但是您的示例代码显示尝试将小时和分钟存储为小数小时。这已经是有问题的,因为这种关联并不精确。例如,您不能从整数小时和分钟中得到 20.58
小时;你可以接近 (20.58333333...
),但不完全是。
比小数小时更一致的方法是总分钟数。而不是存储
static_cast<double>(hours) + 12.00 + static_cast<double>(mins)/60.00
到一个文件并处理精度问题,你可以通过存储
来获得完美的精度(hours + 12) * 60 + mins
这是一个整数,回避了使用多少位小数的问题。读取保存的值时将恢复完全相同的值。
为人类可读的输出保存小数小时(如果需要),并为需要由程序存储和检索的值使用总分钟数。