c++ - printf 如何从 float 中提取数字?

标签 c++ c floating-point printf

printf 等函数如何从 float 中提取数字?我理解原则上如何做到这一点。给定一个数字 x,您需要其中的前 n 位数字,将 x 缩放为 10 的幂,以便 x 介于 pow(10, n)pow(10, n-1) 之间。然后将x转化为整数,取整数的位数。

我试过了,效果很好。有点。我的答案与 printf 给出的前 16 位十进制数字的答案相同,但在后面的数字上往往有所不同。 printf 是怎么做到的?

最佳答案

经典实现是 David Gay 的 dtoa .确切的细节有些神秘(请参阅 Why does "dtoa.c" contain so much code? ),但通常它的工作原理是使用比 32 位、64 位甚至 80 位 float 更高的精度进行基本转换。为此,它使用所谓的“bigints”或任意精度数字,它可以在内存中容纳尽可能多的数字。 Gay 的代码经过修改后已被复制到无数其他库中,包括 C 标准库的通用实现(因此它可能为您的 printf 提供支持)、Java、Python、PHP、JavaScript 等。

(附带说明...并非所有这些 Gay 的 dtoa 代码拷贝都保持最新,因此因为 PHP 使用 strtod 版本,它在解析 2.2250738585072011e-308 时挂起.)

一般来说,如果你用“明显”和简单的方式做事,比如乘以 10 的幂然后转换整数,你会损失少量的精度并且一些结果会不准确......但是也许你会得到正确的前 14 或 15 位数字。 Gay 的 dtoa() 实现声称所有数字都是正确的……但结果是,代码很难理解。跳到底部查看 strtod 本身,您可以看到它以仅使用普通浮点运算的“快速路径”开始,但随后它会检测该结果是否不正确并使用更可靠的算法使用 bigints 在所有情况(但速度较慢)。

该实现有以下引用,您可能会发现它很有趣:

 * 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 算法,

The algorithm uses exact rational arithmetic to perform its computations so that there is no loss of accuracy. In order to generate digits, the algorithm scales the number so that it is of the form 0.d1d2..., where d1, d2, ..., are base-B digits. The first digit is computed by multiplying the scaled number by the output base, B, and taking the integer part. The remainder is used to compute the rest of the digits using the same approach.

然后算法可以继续,直到它得到准确的结果(这总是可能的,因为 float 以 2 为底,而 2 是 10 的因数)或直到它有与请求一样多的数字。论文接着证明了算法的正确性。


另请注意,并非所有 printf 的实现都基于 Gay 的 dtoa,这只是一个被大量复制的特别常见的实现。

关于c++ - printf 如何从 float 中提取数字?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51052417/

相关文章:

floating-point - OCaml 中的 C99 风格的十六进制浮点常量

c++ - 如何解决无法在 C++ 中重载返回类型的问题

c++ - 从cmake禁用Google测试的所有警告

C++ SDL 通过单击进行点对点角运动

c - 任何类型的一般排序,与结构作斗争

c - 未定义对 sem_init 和其他此类函数的引用,即使使用了 -lpthread 和 -ltr

c - 进程与信号同步

javascript - 如何在 Javascript 中获取 float 的小数位?

c++ - std::array 的大小是否由标准定义

actionscript-3 - 将十六进制字符串转换为单精度 ActionScript 3.0