C语言float内存布局示例详解

 更新时间:2023年09月12日 10:38:40   作者:不停感叹的老林  
这篇文章主要为大家介绍了C语言float内存布局示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

前言

C语言中的float并不像大多数人想象的那样, 由于计算机模拟的原因, 其本质是离散的而非连续的, 所以精度和范围是一定的, 这些都写在float.h头文件的宏中.

但通常, 我们对教材的每一个字都认识, 连起来就读不懂了, 所以, 写下此博文, 详解之.

学过深入理解计算机系统的同学, 都知道float的实现方式, 按照IEEE标准, 由符号位, 阶码位, 尾数位组成, 本文给出一个代码, 打印float的符号位, 阶码位, 尾数位.

一、float中的宏定义

这是float.h中有关float具体实现, 范围, 精度等的宏常量, 依据64位系统环境, 我们逐个解读.

#include <float.h>
    FLT_RADIX;      // 2;
    FLT_MANT_DIG;   // 24;
    FLT_DIG;        // 6;
    FLT_MIN_10_EXP; // (-37);
    FLT_MAX_10_EXP; // 38;
    FLT_EPSILON;    // 1.19209290e-7F;
    FLT_MAX;        // 3.40282347e+38F;
    FLT_MIN;        // 1.17549435e-38F;

FLT_RADIX 2

This is the value of the base, or radix, of the exponent representation. This is guaranteed to be a constant expression, unlike the other macros described in this section. The value is 2 on all machines we know of except the IBM 360 and derivatives.

这是指数表示的基数或基数的值。这保证是一个常量表达式,与本节中描述的其他宏不同。在我们所知的所有机器上,该值均为 2,除了 IBM 360 及其衍生产品。

float基于二进制实现, 其基数是2.

换句人话说, 所有float浮点数, 都是由一系列2的n次方相加组成.

比如

0.5 就是
2^-1 次方,

0.25就是
2^-2 次方,

0.75就是
2^-1 + 2^-2

FLT_MANT_DIG 24

This is the number of base-FLT_RADIX digits in the floating point mantissa for the float data type. The following expression yields 1.0 (even though mathematically it should not) due to the limited number of mantissa digits:

这是浮点数据类型的浮点尾数中的基数FLT_RADIX位数。由于尾数位数有限,以下表达式产生 1.0(尽管在数学上不应该产生):

float radix = FLT_RADIX; // 2.0
1.0f + 1.0f / radix / radix / … / radix; //在float中, 1.0 其实是 1.0 + 1.0 连续除以 24 个 2.0

where radix appears FLT_MANT_DIG times.

radix 出现了FLT_MANT_DIG 次, 也就是 24 次.

这个细节如果有人看过深入理解操作系统, 那么就应该明白了, 在IEEE标准中, float的尾数是23位, 但由于通常都是1.0+0.N的形式, 所以相当于第一位是隐式的1, 加23位就是24位.

这24位就是float的二进制精度.

FLT_DIG 6

float的十进制精度, 包括整数部分及小数部分.

比如 123.456 这就是6位精度, 再多就不保证精度可用了, 比如123.4567, 其中7就不保证是正确的.

FLT_MIN_10_EXP (-37)

这代表float能保证的最小的10进制指数, 我这里是 10^-37 次方, 再小就不保证正确了.

FLT_MAX_10_EXP 38

这是float能保证的最大的10进制指数, 再大就不保证正确了

FLT_EPSILON 1.19209290e-7F

这个不好理解, 它的意思是 1.0 和比 1.0 大的最小的float值的差.

FLT_MAX 3.40282347e+38F

float能表示的最大数.

FLT_MIN 1.17549435e-38F

float能表示的最小数.

二、float 内存布局打印实现算法

基本思想是实现一个位域结构, 将一个32位的整数分成三份, 一份占1位, 指示符号, 一份占8位, 指示阶码, 一份占23位, 指示尾数.

typedef struct
{
    uint32_t Mantissa : 23;
    uint32_t Exponent : 8;
    uint32_t Sign : 1;
} fltToBit;

由于是小端序, 逆着排, 也就是尾数, 阶码, 符号.

通过itoa()函数, 将整数转为二进制字符串, 并进行打印.

float 内存布局打印实现代码

代码比较容易, 唯一不好理解的是:

fltToBit test = *(fltToBit *)&a;

float 不能直接强制转为 fltToBit, 需要先取地址, 强转为 fltToBit 指针, 再解引用.

其他的代码都应该能懂.

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
    uint32_t Mantissa : 23;
    uint32_t Exponent : 8;
    uint32_t Sign : 1;
} fltToBit;
void print_float_as_binary(float a)
{
    char BufExponet[32] = "";
    char BufMantissa[32] = "";
    fltToBit test = *(fltToBit *)&a;
    printf("Sign: %u\nExponent: %08s\nMantissa: %023s\n", test.Sign,
           itoa(test.Exponent, BufExponet, 2),
           itoa(test.Mantissa, BufMantissa, 2));
}
int main()
{
    const float a = 1.4142136F;
    print_float_as_binary(a);
    return 0;
}

总结

float 是用离散方法实现有限精度的浮点数, 有时间应仔细查阅文档进行推敲, 很有意思.

本文介绍了IEEE对float的实现, 利用数据结构, 将其内部真实二进制值打印出来, 方便读者研究。

更多关于C语言float内存布局的资料请关注脚本之家其它相关文章!

相关文章

  • c++实现的常见缓存算法和LRU

    c++实现的常见缓存算法和LRU

    LRU缓存算法也叫LRU页面置换算法,是一种经典常用的页面置换算法,下面这篇文章主要介绍了c++实现的常见缓存算法和LRU,需要的朋友可以参考借鉴,下面来一起看看吧。
    2017-01-01
  • C++ list-map链表与映射表的简单使用

    C++ list-map链表与映射表的简单使用

    本文主要介绍了C++ list-map链表与映射表的简单使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-05-05
  • C++如何删除map容器中指定值的元素详解

    C++如何删除map容器中指定值的元素详解

    map容器是C++ STL中的重要一员,删除map容器中value为指定元素的问题是我们经常与遇到的一个问题,下面这篇文章主要给大家介绍了关于利用C++如何删除map容器中指定值的元素的相关资料,需要的朋友可以参考借鉴,下面来一起看看吧。
    2017-06-06
  • C语言动态内存分配图文讲解

    C语言动态内存分配图文讲解

    给数组分配多大的空间?你是否和初学C时的我一样,有过这样的疑问。这一期就来聊一聊动态内存的分配,读完这篇文章,你可能对内存的分配有一个更好的理解
    2023-01-01
  • 详解C语言之实现通讯录

    详解C语言之实现通讯录

    这篇文章主要为大家详细介绍了用C语言实现通讯录,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-11-11
  • C++中智能指针unique_ptr的实现详解

    C++中智能指针unique_ptr的实现详解

    智能指针本质上并不神秘,其实就是 RAII 资源管理功能的自然展现而已,这篇文章主要为大家详细介绍了如何实现 C++中智能指针的 unique_ptr,需要的可以了解下
    2024-01-01
  • C++数组去重十种方法

    C++数组去重十种方法

    数组去重是一个常见的操作,本文主要介绍了C++数组去重十种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-03-03
  • C++中std::find函数介绍和使用场景

    C++中std::find函数介绍和使用场景

    std::find函数是一个非常实用的通用查找算法,适用于各种场景,本文主要介绍了C++中std::find函数介绍和使用场景,具有一定的参考价值,感兴趣的可以了解一下
    2024-02-02
  • VScode运行C++中文终端乱码的解决方案

    VScode运行C++中文终端乱码的解决方案

    这篇文章主要介绍了VScode运行C++中文终端乱码的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-01-01
  • C语言中pthread_exit和pehread_join的使用

    C语言中pthread_exit和pehread_join的使用

    pthread_exit用于强制退出一个线程,pthread_join用于阻塞等待线程退出,获取线程退出状态,本文主要介绍了C语言中pthread_exit和pehread_join函数的使用,具有一定的参考价值,感兴趣的可以了解一下
    2024-02-02

最新评论