查看: 312|回复: 1|关注: 0

[话题讨论] 浮点数在内存中表示方式的理解

[复制链接]

论坛优秀回答者

18

主题

1905

帖子

408

最佳答案
  • 关注者: 80
发表于 2019-5-22 10:01:13 | 显示全部楼层 |阅读模式
本帖最后由 深蓝孩童 于 2019-5-22 10:09 编辑

论坛有很多讨论浮点数误差的帖子,会说到浮点数的表示方法。这里简要记录一下我的理解,因为重复了对于浮点数学习的过程,觉得还是需要有一些记录,主要是single和double类型的在内存中表示方法的验证。
参考文档https://blogs.mathworks.com/cleve/2014/07/07/floating-point-numbers/?s_tid=srchtitle
https://blogs.mathworks.com/loren/2006/08/23/a-glimpse-into-floating-point-accuracy/?s_tid=srchtitle
https://www.mathworks.com/content/dam/mathworks/mathworks-dot-com/company/newsletters/news_notes/pdf/Fall96Cleve.pdf
  1. number_dec = single(120.45)
  2. hexString = num2hex(number_dec) % sprintf('%tx', number_dec)
  3. binString = dec2bin(hex2dec(hexString));
  4. binString = [char(zeros(1,32-length(binString)) + 48) binString]
  5. number_transform = (1 + single(bin2dec(binString(10:end)))/2^23)*2^(bin2dec(binString(2:9)) - 127) % 按照single数据的表示方式来求得十六进制对应的浮点数
复制代码
  1. number_dec = 8.5
  2. hexString = num2hex(number_dec) % sprintf('%bx', number_dec)
  3. binString = dec2bin(hex2dec(hexString));
  4. binString = [char(zeros(1,64-length(binString)) + 48) binString]
  5. (1 + bin2dec(binString(13:end))/2^52)*2^(bin2dec(binString(2:12)) - 1023) % 按照double数据的表示方式来求得十六进制对应的浮点数
  6. hex2num(hexString) % 十六进制转化为浮点数
复制代码

再有julia的相关代码:


  1. # half类型表示方式
  2. a = Float16(8.5f0)
  3. println("数值:", a, " 类型:", typeof(a))
  4. s = bitstring(a)
  5. println("十六进制表示:0x", string(parse(UInt16, s, base=2), base=16, pad=4))
  6. println("bitstring: ", s, " 比特长度:", length(s))
  7. print("第一个比特:", s[1])
  8. print(" 阶码比特:", s[2:6])
  9. println(" 尾数比特:", s[7:end])
  10. exp = parse(UInt16, s[2:6], base = 2)
  11. res = parse(UInt64, s[7:end], base = 2)
  12. println((1 + res/2^10)*2.0^(exp - 15))
  13. # single类型表示方式
  14. println(repeat("#", 64))
  15. a = 8.5f0
  16. println("数值:", a, " 类型:", typeof(a))
  17. s = bitstring(a)
  18. println("十六进制表示:0x", string(parse(UInt32, s, base=2), base=16, pad=4))
  19. println("bitstring: ", s, " 比特长度:", length(s))
  20. print("第一个比特:", s[1])
  21. print(" 阶码比特:", s[2:9])
  22. println(" 尾数比特:", s[10:end])
  23. exp = parse(UInt8, s[2:9], base = 2)
  24. res = parse(UInt32, s[10:end], base = 2)
  25. println((1 + res/2^23)*2^(exp - 127))
  26. # double类型表示方式
  27. println(repeat("#", 64))
  28. a = 8.5
  29. println("数值:", a, " 类型:", typeof(a))
  30. s = bitstring(a)
  31. println("十六进制表示:0x", string(parse(UInt64, s, base=2), base=16, pad=8))
  32. println("bitstring: ", s, " 比特长度:", length(s))
  33. print("第一个比特:", s[1])
  34. print(" 阶码比特:", s[2:12])
  35. println(" 尾数比特:", s[13:end])
  36. exp = parse(UInt16, s[2:12], base = 2)
  37. res = parse(UInt64, s[13:end], base = 2)
  38. println((1 + res/2^52)*2^(exp - 1023))
  39. # 十六进制转化为浮点数
  40. nTemp = 0x00010101
  41. println(typeof(nTemp))
  42. reinterpret(Float32, nTemp)
复制代码
C++代码(参考网上博客)
  1. #include <iostream>

  2. using namespace std;

  3. int main()
  4. {
  5.         float single_number = 120.45f;
  6.         unsigned char* single_number_ptr = (unsigned char*)& single_number;
  7.         for (int i = 3; i >= 0; i--)
  8.                 printf("%2X", single_number_ptr[i]);

  9.         cout << endl;

  10.         double double_number = 120.45;
  11.         unsigned char* double_number_ptr = (unsigned char*)& double_number;
  12.         for (int i = 7; i >= 0; i--)
  13.                 printf("%2X", double_number_ptr[i]);

  14.         return 0;
  15. }
复制代码
相应的结果分别为:
matlab_19a win10.png julia 1.1,win10.png c++ vs2019 win10.png




多看帮助文档
说明你的matlab版本

论坛优秀回答者

18

主题

1905

帖子

408

最佳答案
  • 关注者: 80
 楼主| 发表于 2019-5-26 15:17:46 | 显示全部楼层
本帖最后由 深蓝孩童 于 2019-6-22 18:50 编辑

由浮点数表示方式知道,double类型的指数范围为[-1022,1023],即十一个比特部分为0b000'0000'0001~0b111'1111'1110,同时尾数部分可以包括所有组合,即范围为[0,2^52-1],代表小数部分是[0,(2^52-1)/2^52]。
double类型指数部分两个端点值0和1024用来表示特殊的浮点数,指数为1024,小数为0时,表示inf;指数为1024,小数非0时,表示nan,见下图。指数部分都为0的情况见一楼的参考文档2。
批注 2019-05-26 151711.png


多看帮助文档
说明你的matlab版本
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

站长推荐上一条 /3 下一条

快速回复 返回顶部 返回列表