你怎么打印一个浮点数的精确值?你怎么、精确、浮点数

2023-09-10 22:54:48 作者:网名和头像私奔了

首先,这不是一个浮点新手问题。我知道浮点运算(更不要说超越函数)通常不能被重新presented完全的结果,而且大多数终端小数不能重新presented正是因为二进制浮点数。

First of all, this is not a floating point newbie question. I know results of floating point arithmetic (not to mention transcendental functions) usually cannot be represented exactly, and that most terminating decimals cannot be represented exactly as binary floating point numbers.

这是说,每个可能的浮点值完全对应于一个双值理性(有理数 P / Q- ,其中是2的幂),这反过来又重新presentation精确的十进制。

That said, each possible floating point value corresponds exactly to a diadic rational (a rational number p/q where q is a power of 2), which in turn has an exact decimal representation.

我的问题是:你如何找到这个确切的重presentation有效小数? 的sprintf 和类似的功能通常只规定达到一些显著数字来唯一确定原始浮点值;他们不一定再打印presentation准确的十进制。我知道有一个算法,我使用,但它的速度很慢, O(E ^ 2),其中电子是指数。这里有一个大纲:

My question is: How do you find this exact decimal representation efficiently? sprintf and similar functions are usually only specified up to a number of significant digits to uniquely determine the original floating point value; they don't necessarily print the exact decimal representation. I know one algorithm I've used, but it's very slow, O(e^2) where e is the exponent. Here's an outline:

尾数转换为十进制整数。你可以做到这一点,拉开位直接读取尾数,也可以写第一乘以二的幂的值,把它的范围1℃的凌乱的浮点循环= X小于10,然后再换关闭一个数字在时间铸造为int,减去,并乘以10。 在反复乘以或除以2,这是十进制数字在字符串您产生的操作应用的指数。每3〜乘法将增加一个额外的位左移。每一个dividion将增加一个额外的数字,以正确的。 Convert the mantissa to a decimal integer. You can either do this by pulling apart the bits to read the mantissa directly, or you can write a messy floating point loop that first multiplies the value by a power of two to put it in the range 1<=x<10, then pulls off a digit at a time by casting to int, subtracting, and multiplying by 10. Apply the exponent by repeatedly multiplying or dividing by 2. This is an operation on the string of decimal digits you generated. Every ~3 multiplications will add an extra digit to the left. Every single dividion will add an extra digit to the right.

这真的是最好的?我对此表示怀疑,但我不是一个浮点专家,我无法找到一个方法来做到以10为计算对数的浮点再presentation不运行到不精确结果的可能性(乘或什么,但2的动力分配是浮点数,除非你知道你有空闲位一起工作)有损耗的操作。

Is this really the best possible? I doubt it, but I'm not a floating-point expert and I can't find a way to do the base-10 computations on the floating point representation of the number without running into a possibility of inexact results (multiplying or dividing by anything but a power of 2 is a lossy operation on floating point numbers unless you know you have free bits to work with).

推荐答案

这个问题有一个官僚部分和算法部分。浮点数在内部存储为2 ^ E * m,其中e是指数(本身二进制),m是一个尾数。问题的官僚部分是如何访问这些数据,但R.似乎更感兴趣的问题算法的一部分,也就是将2 ^ E *米到一小部分的A / B十进制形式。在几种语言的答案官僚问题是frexp(这是一个有趣的细节,我不知道今天之前)。

This question has a bureaucratic part and an algorithmic part. A floating point number is stored internally as 2^e*m, where e is an exponent (itself in binary) and m is a mantissa. The bureaucratic part of the question is how to access this data, but R. seems more interested in the algorithmic part of the question, namely converting 2^e*m to a fraction a/b in decimal form. The answer to the bureaucratic question in several languages is "frexp" (which is an interesting detail that I didn't know before today).

这是事实,乍一看,它需要O(E ^ 2)工作只是写2 ^ E十进制,多的时候仍然是尾数。但是,由于 Schonhage-Strassen的神奇的快速乘法算法,可以在O-波浪(五)的时候,那里的波浪手段达到日志因素做到这一点。如果你查看​​Schonhage-Strassen的魔术,那么它并不难想到什么就做什么。如果e是偶数,可以递归地计算2 ^(θ/ 2),然后用快速乘法方它。在另一方面,如果e是奇数,你可以递归计算2 ^(E-1),然后双击它。你必须要注意检查,有在基地10版本Schonhage-施特拉森虽然它没有被广泛记载,它可以在任何基本完成。

It is true that at first glance, it takes O(e^2) work just to write 2^e in decimal, and more time still for the mantissa. But, thanks to the magic of the Schonhage-Strassen fast multiplication algorithm, you can do it in O-tilde(e) time, where the tilde means "up to log factors". If you view Schonhage-Strassen as magic, then it's not that hard to think of what to do. If e is even, you can recursively compute 2^(e/2), and then square it using fast multiplication. On the other hand if e is odd, you can recursively compute 2^(e-1) and then double it. You have to be careful to check that there is a version of Schonhage-Strassen in base 10. Although it is not widely documented, it can be done in any base.

从二进制转换很长的尾数为10进制是不完全一样的问题,但它有一个类似的回答。你可以把尾数成两半,米=一个* 2 ^ K +湾然后递归转换A和B为10进制,转换成2 ^ k以10进制,做一套快速乘法计算米的基数为10。

Converting a very long mantissa from binary to base 10 is not exactly the same question, but it has a similar answer. You can divide the mantissa into two halves, m = a*2^k+b. Then recursively convert a and b to base 10, convert 2^k to base 10, and do another fast multiplication to compute m in base 10.

后面这一切的抽象的结果是,你可以转换成整数从一个基站到另一个O型波浪线(N)的时间。

The abstract result behind all of this is that you can convert integers from one base to another in O-tilde(N) time.

如果该问题是关于标准的64位浮点数,那么它太小看中Schonhage-Strassen的算法。在此范围内,则可以改为保存各种花样的工作。一种方法是存储在查找表中的2 ^ E所有2048的值,然后工作在具有非对称乘法(在长乘法和短乘法之间)的尾数。另一个窍门是在基地10000工作(或10更高的功率,这取决于架构),而不是基地10。但是,因为河指出,在评论中,128位浮点数字已经留出足够大的指数调入这两个问题的查找表和标准的长乘法。作为一个实际问题,长的乘法是最快达到少数位数字,则在一个显著介质范围中的一个可以使用 Karatsuba的乘法或 TOOM库克乘法,并在那之后Schonhage - 施特拉森的变化是最好的不仅在理论上,而且在实践中。

If the question is about standard 64-bit floating point numbers, then it's too small for the fancy Schonhage-Strassen algorithm. In this range you can instead save work with various tricks. One approach is to store all 2048 values of 2^e in a lookup table, and then work in the mantissa with asymmetric multiplication (in between long multiplication and short multiplication). Another trick is to work in base 10000 (or a higher power of 10, depending on architecture) instead of base 10. But, as R. points out in the comments, 128-bit floating point numbers already allow large enough exponents to call into question both lookup tables and standard long multiplication. As a practical matter, long multiplication is the fastest up to a handful of digits, then in a significant medium range one can use Karatsuba multiplication or Toom-Cook multiplication, and then after that a variation of Schonhage-Strassen is best not just in theory but also in practice.

其实,大整数包 GMP 已经有O型波浪线(N)的时间基数转换,以及良好的启发式其中乘算法的选择。他们的解决方案和矿山之间的唯一区别是,而不是做任何大的算术基数为10,他们计算的10座2大的权力,在这个解决方案,他们也需要快速的分裂,但可以从快速乘法任何获得几种方式。

Actually, the big integer package GMP already has O-tilde(N) time radix conversion, as well as good heuristics for which choice of multiplication algorithm. The only difference between their solution and mine is that instead of doing any big arithmetic in base 10, they compute large powers of 10 in base 2. In this solution, they also need fast division, but that can be obtained from fast multiplication in any of several ways.