• python实现float/double的0x转化


    1. 问题引出

    最近遇到了一个小问题,即:

    读取文本文件的内容,然后将文件中出现的数字(包括double, int, float等)转化为16进制0x存储

    原本以为非常简单的内容,然后就着手去写了python,但是写着写着发现不对:

    python貌似没办法直接读取内存数据;
    因此不得不借助于C语言,这样又引出了python如何调用C lib

    开始写c发现又有问题了:

    int 类型的数据和float/double数据在内存中的存储方式是不同的

    因此花了一些力气解决了这些问题,成功得将数字转化为了16进制0x的存储类型,特记录一下,以备后续查询,也可以让有需要的童鞋有个参考。

    2. 基本知识

    完成本实验前,你必须具备以下的基础知识:

    1). float/double在内存中的存储方式

    浮点数在内存中的存储形式为二进制的科学计数法,即
    mark
    mark
    其中,S为符号,P为阶码,F为尾数
    其长度如下表所示:

    总长度 符号 阶码 尾数
    float 32 bit 1 8 23
    double 64 bit 1 11 52

    > **符号位 S:** 0代表正数,1代表负数 > **阶码位 P:** 为unsigned, 计算时候,需要将实际尾数减去`7F`, 即实际计算用的`P=eb-0x7F` > **尾数位 F:** 用二进制科学计算法表示后,去掉前面的恒定`1`,只保留小数点后的二进制数据

    例1:32bit二进制 0x42 0xOA 0x1A 0xA0 转化为十进制浮点数

    符号位:S=0,0x42的最高位为0
    阶码位:0x42<<1=0x84, 0x84-0x7F = 5
    尾数位:0x0A1AA0为换算为十进制然后小数点前加1得到1.0789375

    计算:1.0789375*2^5 = 34.526

    例2:将十进制数50.265转化为32位规格化的浮点数

    N = 50.265
    S = 0
    N/2^P = 1.xxx, 因此,P=5
    F=N/2^P=50.265/32=1.57078125
    由以上可知:
    符号位S=0
    eb = P+0x7F=0x84
    尾数d[2]d[1]d[0]= 0x490F5C

    因此,最终结果为:0x42490F5C (记住eb需要移位哦)

    2). python如何调用C lib

    简单起见,可参考该博客:http://blog.csdn.net/golden1314521/article/details/44055523
    详细内容可参考python官方文档:https://docs.python.org/2/library/ctypes.html

    3. 代码

    I. C 代码:读取float所在的内存地址

    /*
     *Filename: ftoc.c
     */
     
    #define uchar unsigned char
    #define uint unsigned int
    
    void ftoc(float fl, uchar arr[]) 
    {
        void *pf;
        pf = &fl;
    
        uchar i;
        for(i=0; i<4; i++)
        {
            arr[i] = *((uchar *)pf+i);
        }
    
    	return ;
    }
    

    II. 编译此代码为libftoc.so

    gcc -shared -Wl,-soname,libftoc -o libftoc.so -fPIC ftoc.c
    
    • shared: 表示需要编译为动态库(.so)
    • Wl: 告诉编译器将后面的参数传递给链接器
    • soname: 指定了动态库的soname(简单共享名,Short for shared object name)

    更加详细的介绍可参考:http://blog.csdn.net/zhoujiaxq/article/details/10213655

    • o : output,即要编译成目标文件的名字
    • fPIC: 地址无关代码(.so必须加此参数),详情可自行搜索

    III. python 代码

    #!/usr/bin/python
    
    import os
    import ctypes
    
    lib_name = './libftoc.so'   #我自己的 c lib
    
    filename = "rd.txt"
    
    
    f1 = open(filename, 'r')
    f2 = open('result.txt', 'w+')
    
    #-----------------------------------
    #check the number is float or not
    def is_float(s):
        try:
            float(s)
            return True
        except ValueError:
            pass
    
    #-----------------------------------
    
    def ftoc(num):
        number = ctypes.c_float(num) #covert the python type to c type
        arr = ctypes.c_ubyte * 4
        parr = arr(ctypes.c_ubyte(), ctypes.c_ubyte(), ctypes.c_ubyte(), ctypes.c_ubyte())  #create a c-type(unsigned char)  array
    
        #access the c lib
        lib_ftoc = ctypes.CDLL(lib_name)
    
        #call the c lib function!!!
        #after this function, parr contains float's dec_number*4
        lib_ftoc.ftoc(ctypes.c_float(num), parr)
        
        lst=[]
        for i in range(4):
            lst.append(parr[i])
            lst[i] = hex(lst[i])[2:]    #get rid of '0x'
            if(len(lst[i]) < 2):
                lst[i] = '0'+lst[i]     #make data 8-bit
        string = lst[3]+lst[2]+lst[1]+lst[0]
        string = string.upper()         #uppercase the characters
    
        return string
    
    
    #============================================
    # main flow
    #===========================================
    lst = []
    line = f1.readline()
    while line:
        line.strip('
    ')
        lst = line.split()
    
        for i in range(len(lst)):
            #if the number is digit
            if lst[i].isdigit():
                lst[i] = hex(int(lst[i]))
                lst[i] = lst[i][2:]         #get rid of '0x' 
                lst[i] = lst[i].upper()     
                if(len(lst[i]) < 8):
                    lst[i] = '0'*(8-len(lst[i])) + lst[i]
    
            #if the number is float
            else: 
                if is_float(lst[i]):
                    lst[i] = ftoc(float(lst[i]))
    
        for i in range(len(lst)):
            f2.write(lst[i])
            f2.write(' ')
    
        f2.write('
    ')
        
        line = f1.readline()
    
    f2.write('
    ')
    
    f1.close()
    f2.close()
    
    

    VI. 运行结果

    运行前的文档:
    mark

    运行后的结果输出:
    mark

  • 相关阅读:
    图片上传
    解决Vuex持久化插件-在F5刷新页面后数据不见的问题
    vue登录
    拖动排序的vue组件
    vue图片懒加载
    vue中使用图片预加载
    前端架构知识体系
    html判断IE版本
    HighCharts 在IE8下饼图不显示的问题
    新一代调试王者Console
  • 原文地址:https://www.cnblogs.com/Jimmy1988/p/8120277.html
Copyright © 2020-2023  润新知