python中数字与C语言中double结构转换

栏目: C · 发布时间: 7年前

内容简介:python中数字与C语言中double结构转换

最近遇到个问题需要将 C语言 中以double类型存储的数字在 python 中进行转换.

先看看C语言中double类型数据是如何存储的:

使用程序

int main()
{
    int i = 21;
    double d = (double)i;
    printf("%x\n",&d);
    return 0;
}

获取到21转换成double后在内存中存储的值, 具体为

0x00 0x00 0x00 0x00 0x00 0x00 0x35 0x40

由于是小端序, 所以需要看成

0x40 0x35 0x00 0x00 0x00 0x00 0x00 0x00

二进制为

0100000000110101000000000000000000000000000000000000000000000000

共64位.

Google 后得知C语言中double型使用的是 IEEE 754 标准.

在这里可以下载:

https://people.eecs.berkeley.edu/~wkahan/ieee754status/IEEE754.PDF

https://www.csee.umbc.edu/~tsimo1/CMSC455/IEEE-754-2008.pdf

由于我这里只需要大概了解, 所以并没有看文档, 通过网上总结好的资料了解到的信息如下:

IEEE 754 规定单精度浮点数使用4个字节存储, 双精度浮点数使用8个字节存储, 分为三个部分表示: 符号位、阶数、尾数。

单精度格式:

符号位 1位, 从右往左第32位, 0表示正数, 1表示负数

阶数 8位, 从右往左第31-24位,阶数需要在结果上+127

位数 23位, 从右往左第23-1位

双精度格式:

符号位 1位, 从右往左第64位, 0表示正数, 1表示负数

阶数 11位, 从右往左第63-53位,阶数需要在结果上+1023

位数 52位, 从右往左第52-1位

这里以21转为双精度格式为例, 来手工转换一次

0 | 000 0000 0000 | 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000

因为21大于0,所以符号位为0

21转为二进制得‭ 10101‬

使用科学记数法表示为: 1.0101 * 2^4

由于二进制第一位总是1, 所以第1位不记录.

阶数需要加上1023, 得到1027.

使用二进制表示为‭100 0000 0011

得到最终结果 0 | ‭100 0000 0011 | 0101 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000

有两个例外需要注意

  1. 0.0存储为全零.

  2. 无穷大数的阶数全为1, 位数部分全为0, 符号位指示正无穷或负无穷.‬

由上面的资料, 编写了下面代码. 由于没有看到完整文档, 也没有处理异常情况, 所以这段代码在实际使用时, 无法处理一些数字.

def number2double_bin(value):
    mantissa = bin(value)[3:]
    exponent = bin(len(mantissa) + 1023)[2:]
    sig_bit = 1 if value < 0 else 0
    return str(sig_bit).zfill(1) + str(exponent).zfill(11) + str(mantissa).ljust(52, '0')


def double_bin2number(value):
    sig_bit = value[0]
    exponent = int("0b" + value[1:12], 2) - 1023
    mantissa = int("0b1" + value[12:12 + exponent], 2)
    return mantissa if sig_bit == "0" else -mantissa


def number2double_hex(value):
    mantissa = bin(value)[3:]
    exponent = bin(len(mantissa) + 1023)[2:]
    sig_bit = 1 if value < 0 else 0
    dst = str(sig_bit).zfill(1) + str(exponent).zfill(11) + str(mantissa).ljust(52, '0')
    result = "0x"
    for i in range(0, 8):
        jn0 = i * 8
        result += hex(int(
            "0b" + dst[jn0 + 0] + dst[jn0 + 1] + dst[jn0 + 2] + dst[jn0 + 3] + dst[jn0 + 4] + dst[jn0 + 5] + dst[
                jn0 + 6] + dst[
                jn0 + 7], 2))[2:].zfill(2)
    return int(result, 16)


def double_hex2number(value):
    str_hex = hex(value)[2:].zfill(8)
    str_bin = ""
    for i in range(0, 4):
        jn0 = i * 2
        str_bin += bin(int(str_hex[jn0] + str_hex[jn0 + 1], 16))[2:].zfill(8)
    sig_bit = str_bin[0]
    exponent = int("0b" + str_bin[1:12], 2) - 1023
    mantissa = int("0b1" + str_bin[12:12 + exponent], 2)
    return mantissa if sig_bit == "0" else -mantissa

# 使用结果如下
print(double_hex2number(0x4035000000000000))
# 输出 21
print(hex(number2double_hex(21)))
# 输出 0x4035000000000000
print(number2double_bin(21))
# 输出 0100000000110101000000000000000000000000000000000000000000000000
print(double_bin2number("0100000000110101000000000000000000000000000000000000000000000000"))
# 输出 21

使用python中提供的struct.pack和struct.unpack可以更优雅的实现功能

def trans(s):
    return ''.join('%.2x' % x for x in s)

# 十六进制字符串转数字
print(struct.unpack('d', binascii.a2b_hex("0000000000003540"))[0])
# 输出 21

# 数字转十六进制字符串
print(trans((struct.pack('d', 21))))
# 输出 0000000000003540

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

转型之战

转型之战

吴晓波 / 2015-7-1

互联网时代大潮席卷而来,互联网究竟是“魔法手杖”,还是“效率金箍棒”?传统企业如何正确借助和利用互联网思维帮助自身转变思维、完成企业转型升级?本书分两篇,上篇为传统行业互联网转型极具代表性和借鉴意义的案例,下篇精选吴晓波转型大课的独 家内容,梳理了吴晓波、刘伟、刘润、金霞、刘博、赵峰、张蕴蓝、张荣耀、李嘉聪、曾玉波等各行业10位导师关于互联网思维的精华理念和观点,其中囊括各传统行业互联网转型成功的......一起来看看 《转型之战》 这本书的介绍吧!

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

html转js在线工具
html转js在线工具

html转js在线工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试