是否有公式可以找到浮点数中指数或有效位数的位数?

Posted

技术标签:

【中文标题】是否有公式可以找到浮点数中指数或有效位数的位数?【英文标题】:Is there a formula to find the numbers of bits for either exponent or significant in a floating point number? 【发布时间】:2020-06-29 04:29:43 【问题描述】:

最近,我对在浮点数上使用位移位来进行一些快速计算很感兴趣。

为了让它们以更通用的方式工作,我想让我的函数使用不同的浮点类型,可能通过模板,不仅限于floatdouble,还包括“半角”或“四倍宽度”浮点数等等。


然后我注意到:

 - Half   ---  5 exponent bits  ---  10 signicant bits
 - Float  ---  8 exponent bits  ---  23 signicant bits
 - Double --- 11 exponent bits  ---  52 signicant bits

到目前为止,我认为exponent bits = logbase2(total byte) * 3 + 2, 这意味着 128 位浮点数应该有 14 个指数位,而 256 位浮点数应该有 17 个指数位。


但是,后来我了解到:

 - Quad   --- 15 exponent bits  ---  112 signicant bits
 - Octuple--- 19 exponent bits  ---  237 signicant bits

那么,有没有一个公式可以找到它?或者,有没有办法通过一些内置函数来调用它? 首选 C 或 C++,但对其他语言开放。

谢谢。

【问题讨论】:

注意:没有保证,至少没有来自 C++ 标准。实现用于浮点编码的内容由实现者决定,但可能会在 IEEE 浮点标准中定义。 IEEE 754,很常见。 wiki page for IEEE 754 什么会阻止您将计数直接硬编码到您的程序中,因为它们都是标准化的? 任何人都可以定义自己的浮点格式并分配他们认为合适的位。关于 IEEE-754 格式,有几个很好的指针here 关于历史和选择。 @Ranoiaetep 考虑到即使是 256 位浮点数的稀有性,我想说一旦您想要/需要添加支持,除了实际实现 DBL_MANT_DIG 以基数 2 double 的有效位数提供 bits 的数量。可在预处理器时使用。 【参考方案1】:

通过内置函数提供的特性

C++ 通过std::numeric_limits 模板提供此信息:

#include <iostream>
#include <limits>
#include <cmath>


template<typename T> void ShowCharacteristics()

    int radix = std::numeric_limits<T>::radix;

    std::cout << "The floating-point radix is " << radix << ".\n";

    std::cout << "There are " << std::numeric_limits<T>::digits
        << " base-" << radix << " digits in the significand.\n";

    int min = std::numeric_limits<T>::min_exponent;
    int max = std::numeric_limits<T>::max_exponent;

    std::cout << "Exponents range from " << min << " to " << max << ".\n";
    std::cout << "So there must be " << std::ceil(std::log2(max-min+1))
        << " bits in the exponent field.\n";



int main()

    ShowCharacteristics<double>();

样本输出:

浮点基数为 2。 有效数字中有 53 个以 2 为底的数字。 指数范围从 -1021 到 1024。 所以指数字段中必须有 11 位。

C 还通过在&lt;float.h&gt; 中定义的DBL_MANT_DIG 等宏定义提供信息,但标准仅定义类型float(前缀FLT)、doubleDBL)的名称,和 long double (LDBL),因此支持其他浮点类型的 C 实现中的名称将无法预测。

请注意,C 和 C++ 标准中指定的指数与 IEEE-754 中描述的常用指数不同:它被调整为缩放为 [½, 1) 而不是 [1, 2) 的有效数字,所以它比通常的 IEEE-754 指数大一。 (上面的示例显示了从 -1021 到 1024 的指数范围,但 IEEE-754 的指数范围是 -1022 到 1023。)

公式

IEEE-754 确实提供了推荐字段宽度的公式,但它并不要求 IEEE-754 实现符合这些,当然 C 和 C++ 标准也不需要 C 和 C++ 实现符合 IEEE-754。交换格式参数在IEEE 754-2008 3.6中规定,二进制参数为:

对于 16、32、64 或 128 位的浮点格式,有效位宽度(包括前导位)应为 11、24、53 或 113 位,指数字段宽度应为 5、8 、11 或 15 位。 否则,对于k位的浮点格式,k应该是32的倍数,有效位宽度应该是k−round(4•log2k)+13,指数字段应该是round(4•log2k )-13.

【讨论】:

+1 用于跟踪参考。在最后一点可能值得注意的是,该公式仅适用于k &gt;= 128(它实际上也匹配k = 6411 位,但它被12 用于@ 987654336@).【参考方案2】:

答案是否定的。

使用多少位(甚至使用哪种表示)由编译器实现者和委员会决定。并且无法猜测委员会的决定(不,这不是任何合理定义“最佳”的“最佳”解决方案......这正是那天在那个房间发生的事情:历史事故)。

如果你真的想达到那个水平,你需要在你想要部署的平台上实际测试你的代码,并添加一些#ifdef 宏观(或询问用户)以找到你的代码的系统类型正在运行。

另外请注意,根据我的经验,编译器在类型别名方面非常激进(甚至令人讨厌)的一个领域是浮点数。

【讨论】:

最后一段怎么强调都不为过:如果不调用 UB 或通过至少一个 memcpy() 调用,则无法操作浮点位,如果您确实需要结果,则需要两个。即使union 也不足以定义类型双关语。【参考方案3】:

我想看看是否有一个公式是说如果将 512 位浮点数作为标准输入,它会自动使用它,而无需更改任何内容

我不知道有一个已发布的标准可以保证未来格式(*)的位分配。过去的历史表明,最终选择有几个考虑因素,例如,请参阅Why do higher-precision floating point formats have so many exponent bits? 处的答案和链接。(*) 编辑:请参阅末尾添加的注释 em>。

对于猜谜游戏,IEEE-754 定义的现有 5 种二进制格式暗示指数位数的增长略快于线性。例如,适合这 5 个数据点的一个(随机)公式可能是(WA 表示法)exponent_bits = round( (log2(total_bits) - 1)^(3/2) )

这可以预见假设的 binary512 格式将为指数分配 23 位,尽管 IEEE 当然不受这种事后猜测的任何约束。

以上只是一个恰好匹配5个已知指数的插值公式,当然不是唯一这样的公式。例如,在 oeis 上搜索序列 5,8,11,15,19 会找到 18 个列出的整数序列,其中包含该序列作为子序列。


[ EDIT ] 正如@EricPostpischil 的answer 中指出的那样,IEEE 754-2008 实际上列出了total_bits &gt;= 128 的公式exponent_bits = round( 4 * log2(total_bits) - 13 )(公式实际上适用于total_bits = 64,也一样,虽然它不适用于= 32= 16)。

上面的经验公式与128 &lt;= total_bits &lt;= 1472 的参考IEEE 匹配,特别是IEEE 还为binary512 提供23 指数位和binary102427 指数位>.

【讨论】:

这个公式必须是渐近线性的,不管它是如何开始的...... @MadPhysicist 2 b 位值的乘积必须至少线性才能适合 (b+1) 位值,这是一个基本原理在linked 答案中引用。除此之外,我没有看到严格线性的硬性要求,除非施加额外的约束。 如果你想在无穷大时留下任何小数部分,它最多只能是线性的。 @MadPhysicist 我的意思是log2(b) 中的线性。例如,对于指数位和尾数位,上述经验公式的增长速度都快于对数线性增长。【参考方案4】:

与上面提到的概念类似,这里有一个替代公式(只是重新排列了一些项),它将计算指数的无符号整数范围([32,256,2048,32768,524288],对应于 [ 5,8,11,15,19]-powers-of-2) 无需调用 round 函数:

uint_range =  ( 64 **  ( 1 + (k=log2(bits)-4)/2) )
              *
              (  2 ** -(  (3-k)**(2<k)         ) ) 

(a) x ** y 表示 x-to-y-power (b) 2 &lt; k 是一个布尔条件,应该只返回 0 或 1。

函数至少从 16 位到 256 位应该是准确的。除此之外,这个公式产生的指数大小为

   –  512-bit : 23 
   – 1024-bit : 27 
   – 2048-bit : 31 
   – 4096-bit : 35 

(超过 256 可能不准确。即使是 27 位宽的指数也允许 +/- 6700 万的指数,一旦计算出 2 次方,则可以使用超过 4000 万个十进制数字。)

从那里到 IEEE 754 指数只是log2(uint_range) 的问题

【讨论】:

以上是关于是否有公式可以找到浮点数中指数或有效位数的位数?的主要内容,如果未能解决你的问题,请参考以下文章

检查浮点数是否具有指定的位数和小数位数

C++如何用cout控制浮点数输出的位数?

IEEE754表示浮点数

JAVA如何将浮点数输出为指定位数的科学计数法?

JAVA怎么计算txt中一个1亿个浮点数的中位数?

C 语言中双精度浮点型精度怎样保留位数