关于16进制字符串转为单精度浮点数和双精度浮点数的运算(二)

本文详细解析了IEEE64位浮点数格式,包括符号位、阶码及尾数的构成,并通过实例说明如何将十六进制转换为对应的浮点数值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

2.IEEE 64位浮点数格式
这种格式的特点是:每个数由8字节组成,包括1位符号位,11位带符号阶码,52位尾数。
例如:我们收到一个数的格式是 3F F0 6F 80 00 00 00 00,那么它的二进制格式是:
这里写图片描述

0011 1111 1111 0000 0110 1111 1000 0000 0000 0000 0000 0000 0000 0000 0000 0000
这时我们就可以得到这些信息:
符号位:0 (1表明这个数是个负数,0表明这个数是正数)
带符号的阶码:011 1111 1111 (转化为整数是1023)
尾数:0000 0110 1111 1000 0000 0000 0000 0000 0000 0000 0000 0000 0000

首先计算指数:
指数:阶码 - 1023 = 0;表明此尾数不需要移位

然后对尾数进行处理:在尾数的最高位加上一个隐藏位1,形成如下二进制格式:
1 0000 0110 1111 1000 0000 0000 0000 0000 0000 0000 0000 0000 0000
其中小数点的位置就在刚加的隐藏位后,即:
1.0000 0110 1111 1000 0000 0000 0000 0000 0000 0000 0000 0000 0000
次数不用移位,故得到最终的浮点数二进制格式为:
1.0000 0110 1111 1000 0000 0000 0000 0000 0000 0000 0000 0000 0000
计算此二进制格式为
1*(2^-0) + 0*(2^-1) + 1*(2^-2)+ 0*(2^-2) + 1*(2^-3) + 1*(2^-4) + 0*(2^-5) + 1*(2^-6) + 1*(2^-7) + 0*(2^-8) + 1*(2^-9) + 1*(2^-10) +1*(2^-11) + 1*(2^-12) + 1*(2^-13) + 0*(2^-14)+ …. + 0*(2^-52)
计算后的十进制数1.02722168,根据前面的符号位可知,这是个正数,所以最终结果是1.02722168

C语言实现代码

long long int getS(int e,int m)
{
    long long int s=e;
    for (int i=1;i<m;i++)
    {
        s*=e;
    }
    return s;
}
double hex2double(unsigned char*p,double& result)
{
    long long int a=0x0000000000000000;
    a=a|p[0];
    a=(a<<8)|p[1];
    a=(a<<8)|p[2];
    a=(a<<8)|p[3];
    a=(a<<8)|p[4];
    a=(a<<8)|p[5];
    a=(a<<8)|p[6];
    a=(a<<8)|p[7];
    int s=(a>>63)&0xFF;//获得符号位,1表示负数,0表示正数
    int e=(a>>52)&0x7FF;
    e=e-1023;//获得指数
    long long int m=a&0xFFFFFFFFFFFFF|0x10000000000000;//获得底数
    //cout<<setiosflags(ios::uppercase)<<hex<<m<<endl;
    long long int c=0;
    double v=0.0,y=1.0;
    if (e>=0)//向右移动
    {
        c=(m>>(52-e))&0xFFFFFFFFFFFFFFFF;//获得整数的二进制
        long long int b=0;
        for (int i=0;i<52-e;i++)
        {
            b=(b<<1)|0x01;
        }
        b=b&m;//获得小数的二进制
        int j=0;
        for (int i=52-e-1;i>=0;i--)
        {
            j++;
            y=(double)(((b>>i)&0x01)*getS(2,j));
            if (y>0.0)
            {
                v+=1.0/y;
            }
        }
        v=c+v;
        if (s>0)
        {
            v=-v;
        }
    }
    else//向左移动
    {
        e=-e;
        c=m;
        int j=0;
        for (int i=52+e-1;i>=0;i--)
        {
            j++;
            y=(float)(((c>>i)&0x01)*getS(2,j));
            if (y>0.0)
            {
                v+=1.0/y;
            }
        }
        if (s>0)
        {
            v=-v;
        }
    }
    result = v;
    return v;
}

注:做个笔记,以备不时之需。

<think>好的,我现在需要解决用户的问题:如何将16进制换为双精度单精度浮点,并且要考虑大端序。用户希望得到C语言的代码示例以及相关的解释。首先,我需要回忆IEEE 754标准的结构,以及大端序小端序的区别。 对于双精度浮点数,根据IEEE 754,它占用8个字节(64位),其中1位符号位,11位指,52位尾。单精度则是4字节,1位符号,8位指,23位尾换的关键在于将十六进制字符串换为对应的字节组,然后根据端序进行处理,最后进行类型换。 首先,用户提到的是大端序,所以据的高位字节存储在低地址。例如,双精度的字节顺序是第一个字节是最高有效位,最后一个是最低。而C语言中,当我们将字节换为浮点数时,需要考虑系统的字节序是否与大端序一致。如果系统是小端序,就需要将字节组反,再换。 接下来,我需要写出函,将十六进制字符串换为字节组。例如,对于字符串"4048F5C28F5C28F6",每两个字符代表一个字节,换成unsigned char组。然后检查系统是否是大端序,如果不是,反组。最后,将字节换为double或float指针取值。 需要注意的是,直接通过指针换可能存在对齐问题,但在大多平台上,使用memcpy可以避免这个问题。所以更安全的做法是使用memcpy将字节组复制到变量中。 然后,编写示例代码。对于双精度,处理8字节,单精度处理4字节。函可能包括hex_to_bytes,reverse_bytes等辅助函。主函中读取输入字符串换,并打印结果。 现在,需要考虑可能的错误处理,例如输入的十六进制字符串长度是否正确,是否为有效的十六进制字符等,但用户可能只需要基础实现,这部分可以暂时忽略,或者简单处理。 最后,验证示例是否正确。例如,双精度的例子"4048F5C28F5C28F6"对应的十进制值应该是3.14,而单精度的"4048F5C3"换为3.14的近似值。需要确认换后的结果是否正确。 另外,测试系统字节序的函是否正确,使用union来检测系统的端序是否有效。对于大端序系统,不需要反字节;小端序则需要反。 总结步骤: 1. 将十六进制字符串换为字节组。 2. 根据系统端序决定是否反字节组。 3. 使用memcpy将字节组复制到double或float变量中。</think>要将十六进制字符串换为双精度double单精度(float)浮点数(大端序),可以通过以下步骤实现: --- ### **双精度浮点数换代码** ```c #include <stdio.h> #include <stdint.h> #include <string.h> #include <arpa/inet.h> // 仅用于端序检查(可替换) // 将十六进制字符串换为字节组 void hex_to_bytes(const char *hex_str, uint8_t *bytes, size_t byte_len) { for (size_t i = 0; i < byte_len; i++) { sscanf(hex_str + 2*i, "%2hhx", &bytes[i]); } } // 大端序换(若系统是小端序) void reverse_bytes(uint8_t *bytes, size_t len) { for (size_t i = 0; i < len/2; i++) { uint8_t temp = bytes[i]; bytes[i] = bytes[len-1-i]; bytes[len-1-i] = temp; } } double hex_to_double_be(const char *hex_str) { uint8_t bytes[8]; hex_to_bytes(hex_str, bytes, 8); // 检测系统端序(大端序则无需反) uint16_t test = 0x1234; if (*(uint8_t*)&test == 0x34) { // 小端序 reverse_bytes(bytes, 8); } double result; memcpy(&result, bytes, 8); return result; } int main() { const char *hex_double = "4048F5C28F5C28F6"; // 3.14 的大端序表示 double d = hex_to_double_be(hex_double); printf("Double: %.15f\n", d); // 输出:3.140000000000000 return 0; } ``` --- ### **单精度浮点换代码** ```c float hex_to_float_be(const char *hex_str) { uint8_t bytes[4]; hex_to_bytes(hex_str, bytes, 4); // 检测系统端序(大端序则无需反) uint16_t test = 0x1234; if (*(uint8_t*)&test == 0x34) { // 小端序 reverse_bytes(bytes, 4); } float result; memcpy(&result, bytes, 4); return result; } int main() { const char *hex_float = "4048F5C3"; // 3.14 的大端序表示 float f = hex_to_float_be(hex_float); printf("Float: %.7f\n", f); // 输出:3.1400000 return 0; } ``` --- ### **原理解释** 1. **十六进制字节组** 每两个十六进制字符对应一个字节(例如 `"40"` → `0x40`)。 2. **端序处理** - **大端序**:高位字节在前(例如 `0x40` 是双精度的第一个字节)。 - 若系统是小端序,需反字节组后再通过 `memcpy` 换。 3. **类型换** `memcpy` 直接复制字节到浮点数变量,避免指针类型换的未定义行为。 --- ### **端序检测逻辑** - 小端序系统存储 `0x1234` 为 `0x34 0x12`。 - 大端序系统存储 `0x1234` 为 `0x12 0x34`。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

祝云飞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值