J. *_*rez 7 c c++ floating-point printf
如何printf从浮点数中提取数字等函数?我理解原则上可以做到这一点.给定一个x你希望得到第一个n数字的数字,x用10的幂来缩放,这x是在pow(10, n)和之间pow(10, n-1).然后转换x为整数,并取整数的数字.
我尝试了这个,它有效.有点.我的答案与printf前16个十进制数字给出的答案相同,但之后的答案往往不同.怎么printf做?
经典的实施是David Gay dtoa.确切的细节有点神秘(请参阅为什么"dtoa.c"包含如此多的代码?),但一般来说,它的工作方式是使用比32位,64位更高的精度进行基本转换,甚至是80位浮点数.为此,它使用所谓的"bigints"或任意精度数字,它可以保存尽可能多的数字,以适应内存.Gay的代码已经被修改,复制到无数其他库中,包括C标准库的常见实现(因此它可能会支持你printf),Java,Python,PHP,JavaScript等.
(作为旁注...并非所有这些Gay的dtoa代码副本都保持最新,所以因为PHP 在解析2.2250738585072011e-308时使用了旧版本的strtod.)
一般来说,如果你做"明显"和简单的方法,比如乘以10的幂然后转换整数,你将失去一点精度,一些结果将是不准确的......但也许你会得到前14或15位正确.Gay的dtoa()实现声称所有数字都正确...但结果是代码很难遵循.跳到底部看strtod本身,你可以看到它以一个"快速路径"开始,它只使用普通的浮点运算,然后它检测到这个结果是否不正确并使用一个更可靠的算法使用bigint工作在所有情况(但速度较慢).
该实现具有以下引用,您可能会感兴趣:
* Inspired by "How to Print Floating-Point Numbers Accurately" by * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126].
该算法通过计算产生给定二进制数的十进制数范围来工作,并且通过使用更多数字,范围变得越来越小,直到您具有精确结果或者您可以正确舍入到所请求的数字位数.
特别是从sec 2.2算法,
该算法使用精确有理算法来执行其计算,从而不会损失准确性.为了生成数字,算法缩放数字,使其形式为0.d 1 d 2 ...,其中d 1,d 2,...是基数B数字.通过将缩放的数字乘以输出基数B并取整数部分来计算第一个数字.余数用于使用相同的方法计算其余数字.
然后算法可以继续,直到它具有确切的结果(这总是可能的,因为浮点数是基数2,2是因子10)或者直到它具有所请求的数字.本文继续证明算法的正确性.
另请注意,并非所有实现printf都基于Gay的dtoa,这只是一个特别常见的实现,已经被复制了很多.