| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 1444 人关注过本帖
标题:long double在内存中的存储方式
只看楼主 加入收藏
hwl88618
Rank: 1
等 级:新手上路
帖 子:4
专家分:0
注 册:2021-9-26
结帖率:100%
收藏
已结贴  问题点数:20 回复次数:5 
long double在内存中的存储方式
最近在学习浮点数相关的知识,float和double已经能完全理解了,但是long double这个类型,感觉存储的方式很奇怪啊
以最简单的浮点数为例,3.0
按浮点数的存储方式,3.0应该变成1.5 * 2 ^ 1,也就是二进制1.1 * 2 ^ 1,在内存中的存储,符号位是0,指数位最高位为1,后面为0,底数位去掉小数点前的1,最高位1,后面为0
实测,float在内存中是0x40400000,double在内存中是0x40800000 00000000,两者都符合上面的分析
但到了long double,情况完全不一样了。网上查到,float为32位,double为64位,long double为96位,也就是float占4字节,double8字节,long double应该12字节,实测前两者没问题
long double在不同的架构下结果完全不同
在32位x86 centos 7,gcc 4.8.5中,long double长度为12字节,也就是96位,没问题,但到了arm中,同样是centos 7,同样是32位,同样是gcc4.8.5,long double却只有8字节,存储方式跟double完全一样。mips debian 32位中,gcc 8.3,long double跟double也完全一样
到了64位系统中,我分别测试了linux mint 20 gcc 4.8.4,linux mint 20 gcc 9.3和centos 8 gcc 8.3,这三个结果相同,长度都为16字节。
以上是内存占用。然后再说一下具体的存储方式
几个32位系统,除了centos 7 gcc 4.8.5,其他几个都跟double完全一样,就不再讨论了
centos 7 gcc 4.8.5虽然比64位系统中long double小了4字节,但是低位的12字节存储方式是完全一样的,64位系统中高4字节全为0,所以这几个可以一起讨论
按前面说的存储方式,long double的值3.0,理论上应该是最高位符号位为0,指数最高位为1,后面为0,底数位最高位1,后面为0,也就是在内存中应该存储为0x40008000 00000000 00000000
但是,实测发现内存中存储的是这个值:0x00004000 c0000000 00000000
又测试发现-3在内存中是0x0000c000 c0000000 00000000
也就是说,符号位不是96位中的最高位,高16位始终为0,实际占用的只有80位
然后,底数不是刚才分析的最高位1,后面为0,而是最高2位为1,后面为0,底数没有删掉小数点左边的1

贴上我测试用的代码:

程序代码:
#include <stdio.h>
#include <string.h>

int main()
{
    union
    {
        int i[1];
        long double d;
    }u;
    memset(&u, 0, sizeof(u));
    printf("size of void*: %d\n", (int)sizeof(void*));
    printf("size of long double: %d\n", (int)sizeof(long double));
    u.d = 3;
    printf("%llg\n", u.d);
    int i;
    printf("0x");
    for (i = sizeof(u) / sizeof(int) - 1; i >= 0; i--)
    {
        printf("%08X ", u.i[i]);
    }
    printf("\n");
}
搜索更多相关主题的帖子: 内存 字节 long 存储 double 
2021-09-27 15:10
hwl88618
Rank: 1
等 级:新手上路
帖 子:4
专家分:0
注 册:2021-9-26
收藏
得分:0 
另外,怎么在帖子里发图片啊,没找到啊
2021-09-27 15:12
rjsp
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:528
帖 子:9007
专家分:53942
注 册:2011-1-18
收藏
得分:5 
你说得好多,我看晕了(是真晕),大概找到两个提问。

第一个,long double 占用的字节数。
C/C++ 只规定 long double 不小于 double 就行了。比如同样是VC,老版本中是10bytes(80bits),新版本中就降到与double一样。而gcc等中,虽一直用的是80bits有效位,但为了4字节对齐,用了12bytes,前面就补零了。
a. 之所以80bits,那是CPU的数字协处理器(80387)规定的“临时实数”。
b. GCC中long double有效成分就是上述的“80bits临时实数”,再4字节对齐,前面补零。
c. 新版VC中 long double 就是 double,那是因为Intel/AMD等一直不喜欢80387,更喜欢MMX/SSE等
d. MMX/SSE/SSE2等等都不支持“80bits临时实数”,精度不足,编译器一般都会提供128bits的模拟浮点数

第二个,“应该存储为0x40008000 00000000 00000000。但是,实测发现内存中存储的是这个值:0x00004000 c0000000 00000000”
二进制的科学计数法,开头的必然是“1.”,比如 1.011*2^n 完全可以省略掉开头的 1。于是 float/double 就省了它。
“80bits临时实数”说,我够长,不用省,于是就没省。
2021-09-27 16:11
hwl88618
Rank: 1
等 级:新手上路
帖 子:4
专家分:0
注 册:2021-9-26
收藏
得分:0 
回复 3楼 rjsp
也就是说80位够用,有钱任性呗
话说,我查了一下,80387是好老的东西了,至少20多年的历史了,现在还在用这个吗?为什么这么多年了,没有往更多的位数上发展,反而像你说的,long double降成了跟double一样?
硬件这方面,应该怎么学呢,有哪些资料可以参考呢?
2021-09-27 16:37
rjsp
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:528
帖 子:9007
专家分:53942
注 册:2011-1-18
收藏
得分:5 
下班前侃一会儿

一开始CPU是没有浮点运算能力的,怎么办呢?在CPU外增加一个“数字协处理器”。
既然CPU叫8086、80286、80386,那“数字协处理器”就叫8087、80287、80387。
既然所有人都需要“数字协处理器”,那“数字协处理器”就集成到CPU里面去吧。
80486、80586、…… 呢,还是80387,人们对浮点数的需求没增加,那就懒得升级了。
80387是协处理器,这个“协”导致它工作时是会打断CPU流程的,毕竟“协”不是自家人,如同“协管”不是“交警”,处理问题时得“交警”在场。
Intel/AMD等就想干掉80387,用MMX/SSE等替代,悲伤的是,80387真被替代了。

为什么要悲伤,还得从盘古开天地说起。
“数字协处理器”制定位宽,最终决定32bits的float(24bits有效数)、64bits的double(53bits有效数)比较合适,既不太大(太大耗总线、耗处理能力),精度嘛,也足够。节约用float、要精度的用double。
但有个问题呀,这 float/doube 存的是 结果,还是 中间值?屁话,当然既存中间值也存结果。
那就不对了呀,如果中间计算的临时值是53bits,那结果的53bits就不是那么精确。
举个例子 1.24+1.24=2.48,如果缩成2个有效位,那就是1.2+1.2=2.4,这个2.4的精度太差了(差0.08)
例子举得不好,用幼儿园能理解的话:小朋友们量砖头的总长度,要想结果精确到厘米,那量尺就得精确到毫米。
于是CPU厂家搞了个80bits的long double(64bits有效),其实无论你用 float 也好,double 也好, long double 也罢,在80387内部都是转换成 long double 再计算,算完了,再缩成各自的长度,CPU内部用double。
long double 虽然只是为80387内部计算使用的,但它精度确实高呀,在double不满足精度的场合,long double可以大显身手。
如今,SSE2的如今,80387没有了,它最高只支持double。C/C++代码中超过64bits的浮点运算,要么是CPU模拟的(long double),要么是软件模拟的(__float128等),不是一等公民。
2021-09-27 16:58
自由而无用
Rank: 9Rank: 9Rank: 9
等 级:贵宾
威 望:14
帖 子:61
专家分:1456
注 册:2021-8-9
收藏
得分:0 
https://zhuanlan.
https://www.
2021-09-27 17:17
自由而无用
Rank: 9Rank: 9Rank: 9
等 级:贵宾
威 望:14
帖 子:61
专家分:1456
注 册:2021-8-9
收藏
得分:5 
https://www.
https://grouper.
https://blog.
http://weitz.de/ieee/
http://www.softelectro.ru/ieee754_en.html
https://www.

good luck!
2021-09-27 17:30
自由而无用
Rank: 9Rank: 9Rank: 9
等 级:贵宾
威 望:14
帖 子:61
专家分:1456
注 册:2021-8-9
收藏
得分:0 
hi, Mr professor, I m a bit curious about for what you are interested in the memory layout of a high precision data, I guess is that for High Performance Cluster?
2021-09-27 17:50
自由而无用
Rank: 9Rank: 9Rank: 9
等 级:贵宾
威 望:14
帖 子:61
专家分:1456
注 册:2021-8-9
收藏
得分:0 
oh, it seems that I got the point, just like designing a polynomial_add function, it could be optimized by trimming the unnecessary data, close to a compressing algorithm, am I right
2021-09-27 18:26
自由而无用
Rank: 9Rank: 9Rank: 9
等 级:贵宾
威 望:14
帖 子:61
专家分:1456
注 册:2021-8-9
收藏
得分:0 
free download
gog: 80387_Programmers_Reference_Manual_1987
图片附件: 游客没有浏览图片的权限,请 登录注册
2021-09-27 20:05
快速回复:long double在内存中的存储方式
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.019545 second(s), 10 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved