12
返回列表 发新帖
楼主: qingyun

[PL/SQL] 浮点数 和 原始4个byte的转换

[复制链接]
论坛徽章:
26
ITPUB新首页上线纪念徽章
日期:2007-10-20 08:38:44ITPUB十周年纪念徽章
日期:2011-11-01 16:20:282012新春纪念徽章
日期:2012-01-04 11:49:542013年新春福章
日期:2013-02-25 14:51:24夏利
日期:2013-08-13 23:25:29优秀写手
日期:2013-12-18 09:29:092014年新春福章
日期:2014-02-18 16:41:11马上有车
日期:2014-02-18 16:41:11蓝色妖姬
日期:2015-03-19 09:37:00ITPUB年度最佳技术原创精华奖
日期:2015-03-19 09:43:24
11#
 楼主| 发表于 2017-1-29 18:33 | 只看该作者
本帖最后由 qingyun 于 2017-1-29 18:51 编辑

这段提交报错,以为没成功;

使用道具 举报

回复
论坛徽章:
26
ITPUB新首页上线纪念徽章
日期:2007-10-20 08:38:44ITPUB十周年纪念徽章
日期:2011-11-01 16:20:282012新春纪念徽章
日期:2012-01-04 11:49:542013年新春福章
日期:2013-02-25 14:51:24夏利
日期:2013-08-13 23:25:29优秀写手
日期:2013-12-18 09:29:092014年新春福章
日期:2014-02-18 16:41:11马上有车
日期:2014-02-18 16:41:11蓝色妖姬
日期:2015-03-19 09:37:00ITPUB年度最佳技术原创精华奖
日期:2015-03-19 09:43:24
12#
 楼主| 发表于 2017-1-29 18:34 | 只看该作者
本帖最后由 qingyun 于 2017-1-29 18:50 编辑

其实是项目中用到,称重机设备传过来的是4个字节的单精度数;
解析是做在存储过程里的; 如果解析在前台做,用前台语言,非常方便能处理了;

但是用sql,却发现真的没有现成的函数;被迫无奈,只能动手自己写了;


参考了:
https://www.h-schmidt.net/FloatConverter/IEEE754.html

里面可以做实验验证;

大致思路是:

1. 把这4个字节转换成32个2进制数,形式:

   1位   8位         23位
    X    xxxxxxxx   XXXXXXXXXXXXXXXXXXXXXXX
   符号  阶          尾数

翻译结果是:

      符号* (  POWER(2, 阶-127)  +  0.尾数*POWER(2,阶-127);

为什么这么设计,估算是这样设计最符合 cpu的思维,运算速度最快;


程序如下:



  1. CREATE OR REPLACE FUNCTION HEX_TO_FLOAT(P_HEX VARCHAR2) RETURN binary_float IS

  2. V_HEX VARCHAR2(8); --4个字节
  3. V_BIN VARCHAR2(32); --32个2进制数
  4. V_SIGN VARCHAR2(1); --正数或负数的标记;
  5. V_RESULT binary_float;
  6. V_Exponent PLS_INTEGER; --阶;
  7. V_Mantissa binary_float; --位数;
  8. V_LEN pls_integer;
  9. BEGIN
  10. BEGIN
  11. V_HEX := UTL_RAW.REVERSE(P_HEX); --解析的方式 :从低到高; 但是输入的顺序是:从高到低;
  12. EXCEPTION
  13. WHEN OTHERS THEN
  14. RETURN - 1; --无效的;
  15. END;


  16. --把4个字节转换为32位的2进制;
  17. SELECT LISTAGG(data) WITHIN GROUP(order by rownum)
  18. INTO V_BIN
  19. FROM (SELECT (CASE upper(substr(V_HEX, rownum, 1))
  20. WHEN '0' THEN
  21. '0000'
  22. WHEN '1' THEN
  23. '0001'
  24. WHEN '2' THEN
  25. '0010'
  26. WHEN '3' THEN
  27. '0011'
  28. WHEN '4' THEN
  29. '0100'
  30. WHEN '5' THEN
  31. '0101'
  32. WHEN '6' THEN
  33. '0110'
  34. WHEN '7' THEN
  35. '0111'
  36. WHEN '8' THEN
  37. '1000'
  38. WHEN '9' THEN
  39. '1001'
  40. WHEN 'A' THEN
  41. '1010'
  42. WHEN 'B' THEN
  43. '1011'
  44. WHEN 'C' THEN
  45. '1100'
  46. WHEN 'D' THEN
  47. '1101'
  48. WHEN 'E' THEN
  49. '1110'
  50. WHEN 'F' THEN
  51. '1111'
  52. END) data
  53. FROM dual
  54. CONNECT BY rownum <= 8);


  55. V_SIGN:=SUBSTR(V_BIN,1,1); --获取正数或负数符号; 0是正数 1是负数


  56. --获取第2~9这8个数的10进制数值;
  57. SELECT SUM(data1)
  58. into V_Exponent
  59. FROM (SELECT substr(substr(V_BIN, 2, 8), rownum, 1) *
  60. power(2, 8 - rownum) data1
  61. FROM dual
  62. CONNECT BY rownum <= 8);

  63. --数值减去127 就是阶;
  64. V_Exponent := V_Exponent - 127;


  65. V_BIN := RTRIM(substr(V_BIN, 10), '0'); --尾数部分;

  66. --尾数的长度
  67. v_len:=length(v_bin);


  68. --计算尾数的值;
  69. V_Mantissa:=0;
  70. for i in 1..v_len
  71. loop
  72. IF SUBSTR(v_bin,I,1)='1'
  73. THEN
  74. V_Mantissa:=V_Mantissa+power(2,-i+V_Exponent);
  75. END IF;
  76. end loop;


  77. --计算真实的值;
  78. V_RESULT:= POWER(2, V_Exponent)+ V_Mantissa;
  79. if V_SIGN='1'
  80. then
  81. V_RESULT:=-V_RESULT;
  82. end if;

  83. return V_RESULT;

  84. EXCEPTION
  85. WHEN OTHERS THEN
  86. RETURN - 1;

  87. END;
复制代码

不过发现 oracle 的存储方式和标准的IEEE不太一样;

比如:
select dump(cast(1.77 as binary_float),16) from dual;
------------------
Typ=100 Len=4: bf,e2,8f,5c   ( 这个的bf应该是3f);
这个结果按标准的ieee方法,应该是-1.77;


但是如果真的是解析:-1.77

select dump(cast(-1.77 as binary_float),16) from dual;
------------------
Typ=100 Len=4: 40,1d,70,a3

发现正负相同的数,解析结果又大相径庭;
不管这些了,总之问题解决了;



使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表