我想以有效的方式删除C ++中浮点数的最后2或3位有效数字。为了更准确地表达问题 - 我想在浮点数表示中丢弃最后几个尾数位。
一些背景:我可以使用不同的方式到达相同的浮点数。例如,如果我在矩形中使用双线性插值,其角点中的值相等,则由于机器精度限制,结果将在矩形的不同点中的最后几位数中变化。这些偏差的绝对顺序取决于内插值的顺序。例如,如果p [i] ~1e10(i == 1..4,矩形角处的值),则由机器精度引起的插值误差为~1e-4(对于8字节浮点数)。如果p [i] ~1e-10那么误差将是~1e-24。由于插值用于计算一阶或二阶导数,我需要“平滑”这些差异。一个想法是从最终结果中删除最后几位数字。以下是我的看法:
#include <iostream> // std::cout
#include <limits> // std::numeric_limits
#include <math.h> // fabs
template<typename real>
real remove_digits(const real& value, const int num_digits)
{
//return value;
if (value == 0.) return 0;
const real corrector_power =
(std::numeric_limits<real>::digits10 - num_digits)
- round(log10(fabs(value)));
//the value is too close to the limits of the double minimum value
//to be corrected -- return 0 instead.
if (corrector_power > std::numeric_limits<real>::max_exponent10 -
num_digits - 1)
{
return 0.;
}
const real corrector = pow(10, corrector_power);
const real result =
(value > 0) ? floor(value * corrector + 0.5) / corrector :
ceil(value * corrector - 0.5) / corrector;
return result;
}//remove_digits
int main() {
// g++ (Debian 4.7.2-5) 4.7.2 --- Debian GNU/Linux 7.8 (wheezy) 64-bit
std::cout << remove_digits<float>(12345.1234, 1) << std::endl; // 12345.1
std::cout << remove_digits<float>(12345.1234, 2) << std::endl; // 12345
std::cout << remove_digits<float>(12345.1234, 3) << std::endl; // 12350
std::cout << std::numeric_limits<float>::digits10 << std::endl; // 6
}
它有效,但使用了2个昂贵的操作 - log10和pow。有更聪明的方法吗?如上所述为实现我的目标,我不需要删除实际的十进制数字,而只需将浮点数的尾数表示中的3-4位设置为0.
答案 0 :(得分:0)
“一些背景:我可以使用不同的方式到达相同的浮点数。”
这不是问题。 x附近的“局部”分辨率约为x-std::next_after(x,0.0)
,在x
范围内,它在很宽的范围内是线性的。 p[i]
变化20个数量级的问题无关紧要,因为相对误差与p[i]
线性变化,这意味着它也会与第一个表达式线性变化。
更一般地说,如果您想比较a
和b
是否足够相似,只需测试a/b
是否约为1.00000000
。 (当b
正好为零时,你遇到了更大的问题 - 没有任何有意义的方法来说明1E-10是否“几乎等于”0)