印花浮子,保持精度
我正在编写一个打印浮点文字的程序,以便在另一个程序中使用。
我需要打印多少位数才能保持原始浮点的精度?
由于浮点数具有24 * (log(2) / log(10)) = 7.2247199
精度的十进制数字,我最初的想法是打印8位数就足够了。 但是,如果我运气不好,那些0.2247199
会分配到7位有效数字的左侧和右侧,所以我应该打印9位小数。
我的分析是否正确? 所有情况下都是9位十进制数字吗? 像printf("%.9g", x);
?
是否有标准函数将float转换为具有该值所需的最小小数位数的字符串,在7或8足够的情况下,所以我不打印不必要的数字?
注意:我不能使用hex浮点文字,因为标准C ++不支持它们。
为了保证二进制 – >十进制 – >二进制往返恢复原始二进制值, IEEE 754要求
The original binary value will be preserved by converting to decimal and back again using:[10] 5 decimal digits for binary16 9 decimal digits for binary32 17 decimal digits for binary64 36 decimal digits for binary128 For other binary formats the required number of decimal digits is 1 + ceiling(p*log10(2)) where p is the number of significant bits in the binary format, eg 24 bits for binary32.
在C中,可用于这些转换的函数是snprintf()和strtof / strtod / strtold()。
当然,在某些情况下甚至更多的数字可能是有用的(不,它们并不总是“噪声”,这取决于十进制转换例程的实现,例如snprintf())。 考虑例如打印二元分数 。
24 *(log(2)/ log(10))= 7.2247199
这对问题很有代表性。 没有任何意义表达有效位数,精度为0.0000001位。 您正在将数字转换为文本,以造福人类 ,而不是机器。 如果你写的话,一个人可能不会在意,也会更喜欢
24 *(log(2)/ log(10))= 7
试图显示8位有效数字只会生成随机噪声数字。 由于浮点误差在计算中累积,因此非零赔率7已经过多。 最重要的是,使用合理的度量单位打印数字。 人们对毫米,克,磅,英寸等感兴趣。 没有建筑师会关心窗口的尺寸比1毫米更准确。 没有窗户制造厂会承诺一个像那样精确的窗户。
最后但同样重要的是,您不能忽略您输入程序的数字的准确性。 无法测量空载欧洲燕子的速度低至7位数。 它大约是每秒11米,最多2位数。 因此,对该速度执行计算并打印具有更多有效数字的结果会产生无意义的结果,从而保证不存在的准确性。
如果该程序是由计算机读取的,我会做一个使用char*
别名的简单技巧。
- 别名
float*
tochar*
- 通过
char*
别名复制到unsigned
(或任何无符号类型足够大) - 打印
unsigned
值
解码只是逆转过程(在大多数平台上,可以使用直接reinterpret_cast
)。
如果你有一个符合C99的C库(如果你的浮点类型的基数是2的幂:), printf
格式字符%a
可以打印浮点值而不会以hexforms的精度,并且实用程序如scanf
和strod
将能够读取它们。
Java中使用的浮点到十进制转换保证产生超出小数点的最小十进制数,以区分数字与其邻居(或多或少)。
您可以从此处复制算法: http : //www.docjar.com/html/api/sun/misc/FloatingDecimal.java.html注意FloatingDecimal(float)
构造函数和toJavaFormatString()
方法。
如果您阅读这些论文(见下文),您会发现有一些算法可以打印最小的十进制数字,以便可以不加改变地重新解释该数字(即通过scanf)。
由于可能有几个这样的数字,算法也会选择最接近原始二进制分数的小数部分(我命名为浮点值)。
遗憾的是C中没有这样的标准库。
你可以使用sprintf
。 我不确定这是否恰好回答了你的问题,但无论如何,这里是示例代码
#include int main( void ) { float d_n = 123.45; char s_cp[13] = { '\0' }; char s_cnp[4] = { '\0' }; /* * with sprintf you need to make sure there's enough space * declared in the array */ sprintf( s_cp, "%.2f", d_n ); printf( "%s\n", s_cp ); /* * snprinft allows to control how much is read into array. * it might have portable issues if you are not using C99 */ snprintf( s_cnp, sizeof s_cnp - 1 , "%f", d_n ); printf( "%s\n", s_cnp ); getchar(); return 0; } /* output : * 123.45 * 123 */
有类似的东西
def f(a): b=0 while a != int(a): a*=2; b+=1 return a, b
(这是Python)你应该能够以无损方式获得尾数和指数。
在C中,这可能是
struct float_decomp { float mantissa; int exponent; } struct float_decomp decomp(float x) { struct float_decomp ret = { .mantissa = x, .exponent = 0}; while x != floor(x) { ret.mantissa *= 2; ret.exponent += 1; } return ret; }
但请注意,仍然不是所有的值都可以用这种方式表示,它只是一个应该给出想法的快速镜头,但可能需要改进。