【发布时间】:2016-01-27 15:02:44
【问题描述】:
在我的程序中,某些双精度数有一些精度(一些正整数,在大多数情况下应该是 的形式),因此double * precision 应该成为一个整数。
但是众所周知浮点数是不准确的,所以,例如1.3029515可以保存为1.3029514999999998...,在我的程序中我需要将这样的浮点数写入文件,但我想要这个@ 987654327@ 代替 1.3029514999999998... 之类的东西。
以前在我的程序中只使用了 形式的精度,而我已经通过如下代码达到了想要的结果:
// I have a function for doubles equality check
inline bool sameDoubles(const double& lhs, const double& rhs, const double& epsilon) {
return fabs(lhs - rhs) < epsilon;
}
inline void roundDownDouble(double& value, const unsigned int& numberOfDigitsInFraction = 6) {
assert(numberOfDigitsInFraction <= 9);
double factor = pow(10.0, numberOfDigitsInFraction);
double oldValue = value;
value = (((int)(value * factor)) / factor);
// when, for example, 1.45 is stored as 1.4499999999..., we can get wrong value, so, need to do the check below
double diff = pow(10.0, 0.0 - numberOfDigitsInFraction);
if(sameDoubles(diff, fabs(oldValue - value), 1e-9)) {
value += diff;
}
};
但是现在,我无法使用相同的技术达到想要的结果,我尝试了以下功能,但没有成功:
// calculates logarithm of number with given base
double inline logNbase(double number, double base) {
return log(number)/log(base);
}
// sameDoubles function is the same as in above case
inline void roundDownDouble(double& value, unsigned int precision = 1e+6) {
if(sameDoubles(value, 0.0)) { value = 0; return; }
double oldValue = value;
value = ((long int)(value * precision) / (double)precision);
// when, for example, 1.45 is stored as 1.4499999999..., we can get wrong value, so, need to do the check below
int pwr = (int)(logNbase((double)precision, 10.0));
long int coeff = precision / pow(10, pwr);
double diff = coeff * pow(10, -pwr);
if(sameDoubles(diff, fabs(oldValue - value), diff / 10.0)) {
if(value > 0.0) {
value += diff;
} else {
value -= diff;
}
}
}
对于1.3029515 值和precision = 2000000,此函数返回不正确的1.302951 值(表达式(long int)(value * precision) 变为等于2605902 而不是2605903)。
我该如何解决这个问题?或者也许有一些聪明的方法可以使这种舍入正确发生?
【问题讨论】:
-
expression (long int)(value * precision) becomes equal to 2605902 instead of 2605903Can't reproduce -
浮点数总是不准确,除非出于某种巧合,它们可以写成 2 的幂之和。例如 0.5 或 0.025,但绝不是 0.1。自己重新生成数字并不会改变这一点,它会使情况变得更糟,因为您添加了计算错误。如果你想公开快乐的整数,那么你必须写 strings.
-
浮点数并非不准确。从字符表示到浮点值的转换通常是不准确的;可以表示为字符序列的值比浮点值多得多。但是,当然,实数的数量也远多于实数的文本表示,所以如果你喜欢说浮点表示不准确,你也可以说数字的文本表示不准确。跨度>
-
@IgorTandetnik,我也无法在一个小测试用例上重现它,实际上在我的大程序中达到了这种情况,我正在从文件中读取双精度并做很多其他的东西.