手工计算浮点数到16进制科学记数法的辅助验证工具

本文介绍了一个用于验证浮点数和双精度浮点数在内存中的16进制科学记数法是否正确的辅助工具。通过此工具,用户可以手动计算浮点数并将其转换为科学记数法,然后使用WinHex进行验证,确保计算的准确性。

手工算浮点数(float or double)到16进制表示的科学记数法(4bytes or 8bytes)时,因为不能马上确定自己算的对不对.

正好刷题时,有一道题,要求将浮点值转成科学记数法. 就直接改成了一个能验证科学记数法是否计算正确的辅助工具~

源码

/// @file exam_2_1.c
/** @brief 
    1.	写出58.25的16进制
    * 这个测试程序是用来确定浮点数在内存中的地址, 当我们手工算完float值后,
      可以WinHex将转换好的16进制浮点数填入内存, 
      然后继续测试程序, 显示我们自己填写的float和double, 看看手算的16进制浮点数是否正确
*/

#include <stdlib.h>
#include <stdio.h>

/// 用CL编译, 不知道为啥不能使用 bool 类型, 自己定义一个
/// error C2065: 'bool' : undeclared identifier
/// bool 不是C语言内建的数据类型么?
#define LS_DEFINE
#ifdef LS_DEFINE
    typedef char bool;
    #define true 1
    #define false 0
#endif // #ifdef LS_DEFINE

#ifndef MAX_PATH
#define MAX_PATH 260
#endif // #ifndef MAX_PATH

void clearScreen(); ///< 清屏
void procTask();

void print_memory_addr_content(unsigned char* pcAddr, int iBytes);
void fill_memory(unsigned char* pcAddr, unsigned char uContent, int iBytes);

int main(int agrc, char** argv)
{
    clearScreen();
    procTask();
    return 0;
}

void procTask()
{
    /// 1.	写出58.25的16进制
    /// 思路
    /// 我们定义一个float fObj,一个double dblObj
    /// 让程序打印出fObj和dblObj的内存地址
    /// 先到了我们暂停的点(等待键盘输入)
    /// 分别算出16进制浮点数后,用WinHex添入fObj的内存地址中和dblObj的内存地址中
    /// 按下让程序继续跑
    /// 让程序打印出fObj和dblObj在内存中的字节内容和float值和double值
    /// 这样就可以验证我们手工计算的float16进制值和double16进制值是否正确
    
    unsigned int uAddrBegin = 0x55AA; ///< 作个内存标记, 可以用来确认winHex打开的地址, 确实是我们的程序
    float fObj = .0f;
    double dblObj = 0;
    unsigned int uAddrEnd = 0xAA55; ///< 作个内存标记, 可以用来确认winHex打开的地址, 确实是我们的程序
    
    printf("sizeof(unsigned int)  = %d, &uAddrBegin = 0x%X\n", sizeof(unsigned int), &uAddrBegin);
    printf("sizeof(float)  = %d, &fObj = 0x%X\n", sizeof(float), &fObj);
    printf("sizeof(double) = %d, &dblObj = 0x%X\n", sizeof(double), &dblObj);
    printf("sizeof(unsigned int)  = %d, &uAddrEnd = 0x%X\n", sizeof(unsigned int), &uAddrEnd);
    
    /// 填充fObj和dblObj到特定的预设值, 方便我们在内存中查找确认要操作的目标
    fill_memory((unsigned char*)&fObj + 0, 0xf0, 1);
    fill_memory((unsigned char*)&fObj + 1, 0xf1, 1);
    fill_memory((unsigned char*)&fObj + 2, 0xf2, 1);
    fill_memory((unsigned char*)&fObj + 3, 0xf3, 1);
    
    fill_memory((unsigned char*)&dblObj + 0, 0xd0, 1);
    fill_memory((unsigned char*)&dblObj + 1, 0xd1, 1);
    fill_memory((unsigned char*)&dblObj + 2, 0xd2, 1);
    fill_memory((unsigned char*)&dblObj + 3, 0xd3, 1);
    fill_memory((unsigned char*)&dblObj + 4, 0xd4, 1);
    fill_memory((unsigned char*)&dblObj + 5, 0xd5, 1);
    fill_memory((unsigned char*)&dblObj + 6, 0xd6, 1);
    fill_memory((unsigned char*)&dblObj + 7, 0xd7, 1);
    
    print_memory_addr_content((unsigned char*)&uAddrBegin, 4);
    print_memory_addr_content((unsigned char*)&fObj, 4);
    print_memory_addr_content((unsigned char*)&dblObj, 8);
    print_memory_addr_content((unsigned char*)&uAddrEnd, 4);
    
    printf("please use winHex fill value to &fObj and &dblObj\n");
    printf("when fill data over, press any key to continue\n");

    /** run result
    sizeof(unsigned int)  = 4, &uAddrBegin = 0x12FF68
    sizeof(float)  = 4, &fObj = 0x12FF64
    sizeof(double) = 8, &dblObj = 0x12FF70
    sizeof(unsigned int)  = 4, &uAddrEnd = 0x12FF6C
    memory addr[12FF68] : AA 55 00 00
    memory addr[12FF64] : F0 F1 F2 F3
    memory addr[12FF70] : D0 D1 D2 D3 D4 D5 D6 D7
    memory addr[12FF6C] : 55 AA 00 00
    please use winHex fill value to &fObj and &dblObj
    when fill data over, press any key to continue
    */
    
    /** 分析
    可以看到变量内存布局和我们定义的顺序并不相同, 由于内存字节对齐的原因
    我们定义的变量顺序为 uAddrBegin => fObj => dblObj => uAddrEnd
    程序编译优化后,改成了
    0x12FF6C uAddrBegin (占用4字节)
    0x12FF70 fObj       (占用4字节) 
    0x12FF74 uAddrEnd   (占用4字节)
    0x12FF78 dblObj     (占用8字节)
    */
    
    /// 在这里计算 fObj = 58.25f 和 dblObj = 58.25 的16进制科学记数法的值
    /**
    ================================================================================
    16进制参考值
    ================================================================================
    0 = 0000 1 = 0001 2 = 0010 3 = 0011 4 = 0100 5 = 0101 6 = 0110 7 = 0111
    8 = 1000 9 = 1001 A = 1010 B = 1011 C = 1100 D = 1101 E = 1110 F = 1111
    
    ================================================================================
    float 值 58.25f 转 科学记数法
    ================================================================================
    58.25f = 58 + 0.25f
    
    * 整数部分 58 转 二进制
    58 / 2 = 29 left 0
    29 / 2 = 14 left 1
    14 / 2 = 7  left 0
    7 / 2 = 3   left 1
    3 / 2 = 1   left 1
    
    从最后一次的除法的商依次念到第一次除法的余数 111010
    so 58 = 111010B
    
    * 小数部分 0.25f 转二进制
    0.25 * 2 = 0.5  up 0
    0.5 * 2 = 0.0   up 1
    从第一次的进位念到最后一次的进位 01
    so 0.25f = .01B
    
    可得
    58.25f = 58 + 0.25f 
        = 111010.01B * 10B^0
        = 1.1101001B * 10B^5
            
    float的科学记数法 S(符号位) = 1, E(指数位) = 8, D(数据位) = 23
    S = 0 (正数)
    E = 127 + 5 = 132D = 10000100B
    D = 1101001000 0000000000 000B
    
    科学记数法值 = SED
    = 0 10000100 1101001000 0000000000 000
    = 0100,0010,0110,1001,0000,0000,0000,0000
    = 4    2    6    9    0    0    0    0
    = 42690000H
    ================================================================================
    double 值 58.25f 转 科学记数法
    ================================================================================
    58.25f = 58 + 0.25f
    
    * 整数部分 58 转 二进制
    58 / 2 = 29 left 0
    29 / 2 = 14 left 1
    14 / 2 = 7  left 0
    7 / 2 = 3   left 1
    3 / 2 = 1   left 1
    
    从最后一次的除法的商依次念到第一次除法的余数 111010
    so 58 = 111010B
    
    * 小数部分 0.25f 转二进制
    0.25 * 2 = 0.5  up 0
    0.5 * 2 = 0.0   up 1
    从第一次的进位念到最后一次的进位 01
    so 0.25f = .01B
    
    可得
    58.25f = 58 + 0.25f 
        = 111010.01B
        = 1.1101001B * 10B^5
            
    float的科学记数法 S(符号位) = 1, E(指数位) = 11, D(数据位) = 52
    S = 0 (正数)
    E = 1023 + 5 = 1028D = 10000000100B
    D = 1101001000 0000000000 0000000000 0000000000 0000000000 00B
    
    科学记数法值 = SED
    = 0 10000000100 1101001000 0000000000 0000000000 0000000000 0000000000 00
    = 0100,0000,0100,1101,0010,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000
    = 4    0    4    D    2    0    0    0    0    0    0    0    0    0    0    0
    = 404D200000000000H

    ================================================================================
    16进制参考值
    ================================================================================
    0 = 0000 1 = 0001 2 = 0010 3 = 0011 4 = 0100 5 = 0101 6 = 0110 7 = 0111
    8 = 1000 9 = 1001 A = 1010 B = 1011 C = 1100 D = 1101 E = 1110 F = 1111

    */

    getchar();

    /// 我们上边已经算出了16进制科学记数法的值, 我们自己写进内存, 和用WinHex手工写是一样的~
    
    // 58.25f = 42690000H
    fill_memory((unsigned char*)&fObj + 0, 0x00, 1);
    fill_memory((unsigned char*)&fObj + 1, 0x00, 1);
    fill_memory((unsigned char*)&fObj + 2, 0x69, 1);
    fill_memory((unsigned char*)&fObj + 3, 0x42, 1);
    
    // 58.25f = 404D200000000000H
    fill_memory((unsigned char*)&dblObj + 0, 0x00, 1);
    fill_memory((unsigned char*)&dblObj + 1, 0x00, 1);
    fill_memory((unsigned char*)&dblObj + 2, 0x00, 1);
    fill_memory((unsigned char*)&dblObj + 3, 0x00, 1);
    fill_memory((unsigned char*)&dblObj + 4, 0x00, 1);
    fill_memory((unsigned char*)&dblObj + 5, 0x20, 1);
    fill_memory((unsigned char*)&dblObj + 6, 0x4d, 1);
    fill_memory((unsigned char*)&dblObj + 7, 0x40, 1);
    
    /// 打印出我们修改后的值
    printf("after you modify, memory below\n");
    print_memory_addr_content((unsigned char*)&uAddrBegin, 4);
    print_memory_addr_content((unsigned char*)&fObj, 4);
    print_memory_addr_content((unsigned char*)&dblObj, 8);
    print_memory_addr_content((unsigned char*)&uAddrEnd, 4);
    
    printf("fObj = %f\n", fObj);
    printf("dblObj = %f\n", dblObj);
    
    /// 程序结束前,停一下, 让我们看看修改的效果
    printf("END, press any key to quit\n");
    getchar();
}

void print_memory_addr_content(unsigned char* pcAddr, int iBytes)
{
    int iIndex = 0;
    
    printf("memory addr[%X] : ", pcAddr);
    for (iIndex = 0; iIndex < iBytes; iIndex++)
    {
        printf("%02X ", *(pcAddr + iIndex));
    }
    
    printf("\n");
}

void fill_memory(unsigned char* pcAddr, unsigned char uContent, int iBytes)
{
    int iIndex = 0;
    
    for (iIndex = 0; iIndex < iBytes; iIndex++)
    {
        *(pcAddr + iIndex) = uContent;
    }
}

void clearScreen()
{
    system("cls");
}

编译脚本

d:\
cd D:\ls\lesson\2015_1023\exam_2_1

del *.exe
del *.obj

"C:\Program Files\Microsoft Visual Studio\VC98\Bin\cl" /c /W3 /WX /O2 exam_2_1.c
"C:\Program Files\Microsoft Visual Studio\VC98\Bin\link" exam_2_1.obj

call exam_2_1.exe
pause

运行效果



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值