深入理解浮点数的表示

浮点数的表示

通常,浮点数表示为:

N=(1)S×M×RE

其中,S取值为0或者1,用来决定浮点数的符号;M是一个二进制定点小数,称为尾数,一般用定点原码小数表示;E是一个二进制顶点整数,称为阶码或者指数,用移码表示。R是基数(隐含),可以约定为2、4、16等

浮点数的表示范围

原码是关于原点对称的,故浮点数的范围也是关于原点对称的,如图2.10所示

img

  • 运算结果大于最大正数时称为正上溢,小于绝对值最大负数时称为负上溢,正上溢和负上溢统称上溢。数据一旦产生上溢,计算机必须中断运算操作,进行溢出处理。
  • 当运算结果在0至最小正数之间时称为正下溢,在0至绝对值最小负数之间时称为负下溢,正下溢和负下溢统称下溢。数据下溢时,浮点数值趋于零,计算机将其当作机器零处理。

浮点数的规格化

为了在浮点数运算过程中尽可能多地保留有效数字的位数,使有效数字尽量占满尾数数位,必须在运算过程中对浮点数进行规格化操作。所谓规格化操作,是指通过调整一个非规格化浮点数的尾数和阶码的大小,使非零浮点数在尾数的最高数位上保证是一个有效值。

  • 左规:当运算结果的尾数的最高数位不是有效位,即出现 ± 0.0...0x...x的形式时,需要进行左规。左规时,尾数每左移一位、阶码减1(基数为2时)。左规可能要进行多次。

  • 右规:当运算结果的尾数的有效位进到数点前面时,需要进行右规,右规只需进行一次。将尾数右移一位、阶码加1(基数为2时)。规时,阶码增加可能导致溢出。

img

注意,当我们在做题的时候,如果题目中没有指明采用的是IEEE754标准,亦没有其他的附加条件,我们应该默认没有隐含位

IEEE754标准

img

img

单精度格式中包含 1 位符号 s、8 位阶码e和 23 位尾数,:双精度格式包含1位符号 s、11位阶码e和 52 位尾数 1。基数隐含为2:尾数用原码表示。对于规格化的二进制浮点数,尾数的最高位总是 1,为了能使尾数多表示一位有效位,将这个1隐藏,称为隐藏位,因此 23 位尾数实际表示了 24 位有效数字。IEEE 754 规定隐藏位1的位置在小数点之前,例如,(12)10=(1100)2,将它规格化后结果为 1.1×23,其中整数部分的“1”将不存储在 23 位尾数内。

单精度与双精度浮点数都采用隐藏尾数最高位的方法,因而使浮点数的精度更高。

在 IEEE 754 标准中,指数用移码表示,但偏置值并不是通常n位移码所用的2n1,而是 2n11因此,单精度和双精度浮点数的偏置值分别为 127 和 1023。在存储浮点数阶码之前,偏置值要先加到阶码真值上。

所以,在IEEE754标准中,规格化单精度浮点数的真值为:

(1)s×1.f×2e127

规格化双精度浮点数的真值为

(1)s×1.f×2e1023

浮点数能表示的范围

img

这个表的意思应该是绝对值的最大值与最小值

阶码为全0或者全1时的特殊意义

img

img

定点、浮点表示的区别

  • 数值的表示范围

    • 若定点数和浮点数的字长相同,则浮点表示法所能表示的数值范围远大于定点表示法。
  • 精度

    • 虽然扩大了数的表示范围,但精度降低了。对于字长相同的定点数和浮点数来说,精度却降低了
  • 数的运算

    • 浮点数包括阶码和尾数两部分,运算时不仅做尾数的运算,还要做阶码的运算,而且运算结果要求规格化,所以浮点运算远比定点运算复杂
  • 溢出问题

    • 在定点运算中,当运算结果超出数的表示范围时,发生溢出;在浮点运算中,运算结果超出尾数表示范围却不一定溢出,只有规格化后阶码超出所能表示的范围时,才发生溢出。

浮点数的机器数

最后我们附上一个将浮点数转为机器数的C++程序,结合机器数来看,可以对浮点数的编码有更好的理解


#include <iostream>
#include <bitset>

int main() {
    float num;
    std::cout << "Please enter a floating-point number: ";
    std::cin >> num;

    union FloatInt {
        float f;
        unsigned int i;
    } data;

    data.f = num;

    // Using union to access the internal representation of the floating-point number
    std::cout << "The machine representation of the floating-point number " << num << " (in hexadecimal): "
              << std::hex << data.i << std::endl; // Print the hexadecimal form

    // Convert the integer to a 32-bit binary string
    std::bitset<32> binaryRepresentation(data.i);
    std::string binaryString = binaryRepresentation.to_string();

    // Splitting into sign, exponent, and mantissa parts
    std::string sign = binaryString.substr(0, 1);
    std::string exponent = binaryString.substr(1, 8);
    std::string mantissa = binaryString.substr(9, 23);

    // Printing the sign, exponent, and mantissa separately
    std::cout << "The machine representation of the floating-point number " << num << " (in binary): " 
              << sign << ";" << exponent << ";" << mantissa << std::endl;

    return 0;
}

作者:AH20

出处:https://www.cnblogs.com/AH20/p/18473990

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   AH20  阅读(232)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
more_horiz
keyboard_arrow_up light_mode palette
选择主题
点击右上角即可分享
微信分享提示