众所周知,浮点数不能完全代表大多数数字。我不是在问浮标或双打精度的问题。
在程序中,浮点数“来自某个地方”。有些可能是通过提升整数来实现的,有些则可能是数字文字。
jQuery(document).ready(function() {
$("div.sidemenugroup h3").hover(function() {
$(this).next("div.sidemenugroup ul").slideDown()
}, function(e) {
$(this).next("div.sidemenugroup ul").slideUp();
});
});
当然,一些浮点数来自涉及其他数字的计算。
int x = 3;
double xd = x;
float xf = 3.0f;
double xd2 = 3.0;
在我的问题中,我有时会从文本文件中读取浮点数,有时候,我会从一个复杂的函数中接收它们,我必须把它当作黑盒子。文本文件的创建者可以选择输入尽可能多的有效数字 - 他们可能只使用三个,或者可能只有八个。
然后我将使用这些数字执行一些计算,我想知道创建它们时隐含了多少重要数字。
对于参数,请考虑我正在对输入点执行自适应分段最小二乘拟合。我将继续分割我的分段,直到达到一定的容差。我希望(部分)基于输入数据的有效数字的公差 - 如果数据四舍五入到最接近的10 ^ -3,则不适合10 ^ -8。
其他人(下方)提出了类似问题(但不完全相同)。例如,我并不特别关注以漂亮的形式向用户输出表示。我并不特别关心从输出文本值中恢复相同的浮点表示。
How to calculate the number of significant decimal digits of a c++ double?
How can I test for how many significant figures a float has in C++?
我想根据双子本身的价值来计算sig figs。我不想对原始数据文件进行大量的文本处理。
在大多数情况下,浮点数最终会以大量的0000000或99999999结尾。一个直观的问题陈述是我有兴趣弄清楚重复0或9序列的开始位置。但是,我宁愿不使用循环舍入的字符串转换方法。我希望有一种相当直接和有效的方法来解决这个问题。
或许在查看最不重要的'on'位然后弄清楚它的大小时这么简单?
答案 0 :(得分:0)
好的,我已经想出了类似的东西......
#include <cstdlib>
#include <cstdio>
#include <cfloat>
#include <cmath>
double sigfigs( double x )
{
int m = floor( log10( std::abs( x ) ) );
double pow10i;
for ( int i = m; i > -26; i-- )
{
pow10i = pow( 10, i );
double y = round( x / pow10i ) * pow10i;
if ( std::abs( x - y ) < std::abs( x ) * 10.0 * DBL_EPSILON )
break;
}
return pow10i;
}
int main( )
{
char fmt[10];
sprintf( fmt, "%%.%de", DBL_DIG + 3 );
double x[9] = {1.0, 0.1, 1.2, 1.23, 1.234, 1.2345, 100.2, 103000, 100.3001};
for ( int i = 0; i < 9; i++ )
{
printf( "Double: " );
printf( fmt, x[i] );
printf( " %f is good to %g.\n", x[i], sigfigs( x[i] ) );
}
for ( int i = 0; i < 9; i++ )
{
printf( "Double: " );
printf( fmt, -x[i] );
printf( " %f is good to %g.\n", -x[i], sigfigs( -x[i] ) );
}
exit( 0 );
}
提供输出:
Double: 1.000000000000000000e+00 1.000000 is good to 1.
Double: 1.000000000000000056e-01 0.100000 is good to 0.1.
Double: 1.199999999999999956e+00 1.200000 is good to 0.1.
Double: 1.229999999999999982e+00 1.230000 is good to 0.01.
Double: 1.233999999999999986e+00 1.234000 is good to 0.001.
Double: 1.234499999999999931e+00 1.234500 is good to 0.0001.
Double: 1.002000000000000028e+02 100.200000 is good to 0.1.
Double: 1.030000000000000000e+05 103000.000000 is good to 1000.
Double: 1.003001000000000005e+02 100.300100 is good to 0.0001.
Double: -1.000000000000000000e+00 -1.000000 is good to 1.
Double: -1.000000000000000056e-01 -0.100000 is good to 0.1.
Double: -1.199999999999999956e+00 -1.200000 is good to 0.1.
Double: -1.229999999999999982e+00 -1.230000 is good to 0.01.
Double: -1.233999999999999986e+00 -1.234000 is good to 0.001.
Double: -1.234499999999999931e+00 -1.234500 is good to 0.0001.
Double: -1.002000000000000028e+02 -100.200000 is good to 0.1.
Double: -1.030000000000000000e+05 -103000.000000 is good to 1000.
Double: -1.003001000000000005e+02 -100.300100 is good to 0.0001.
它似乎主要按预期工作。 pow(10,i)有点不幸,估计数量的基数为10级。
此外,可表示双打之间差异的估计有些粗糙。
是否有人发现任何失败的角落案例?有没有人看到任何明显的方法来改善或优化这个?如果真的很便宜会很好......
罗布
答案 1 :(得分:0)
我建议将问题分为两个步骤:
对于步骤1,您可以使用prior answer中描述的方法,或基于转换为十进制字符串的方法,然后对字符串进行正则表达式分析。 0.1的最小位数确实是1,正如该答案中的算法所报告的那样。
在修复第2步的规则之前,您应该检查由您知道输入有效数字的几组不同实际数字产生的分布。如果问题完全可以解决,那么在所需的位数上应该存在峰值和急剧下降。
考虑案例(0.1 0.234 0.563 0.607 0.89)。步骤1的结果将是:
Digits Count
1 1
2 1
3 3
并计数为4或更高,表示总体上有3位有效数字。