阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

关于MySQL中FLOAT和DOUBLE类型的存储

377次阅读
没有评论

共计 3739 个字符,预计需要花费 10 分钟才能阅读完成。

其实在单精度和双精度浮点类型存储中其存储方式和 C /C++ 一致准守 IEEE 标准他们都是浮点型的,所谓的浮点型,是小数点的位置可变,其能够表示的范围比定点小数要广得多,而存储空间节省,但是受到精度的影响,所以在严格的数据中尽量使用定点小数 MySQL decimal(m,d)类型,Oracle 压根没有浮点数字类型而是 number(p,s)定点小数,

float 4 字节
    1      8      23
  符号位  指数位 尾数

double 8 字节
    1      11    52
    符号位  指数位  尾数
 那么很明显他们的精度取决于尾数。
 而表示的范围取决于指数。

float 表示范围:
2^8=(-128—127)
-2^128—2^127
约为 -3.4E38—3.4E38
 double 表示范围:
2^11=(-1024—1023)
-2^1024—2^1023
约为 -1.7E308—1.7E308
可以看到这个范围实际上很广,但是精度确很小
float 精度:
float 尾数 23 位,2^23=8.3E6  6- 7 位
double 尾数 52 位,2^52=4.5E15 14-15 位

 那么如果使用浮点数据保存了精度大于其范围的数据其会使用四舍五入的方法截断。
MYSQL 如下:
mysql> create table dname(id1 float,id2 double,name varchar(20));
 Query OK, 0 rows affected (0.08 sec)
 mysql> insert into dname values(1234567.123,1234567.123,’gaopeng’);
 Query OK, 1 row affected (0.00 sec)
 mysql> commit;
 Query OK, 0 rows affected (0.00 sec)
 mysql> select * from dname;
 +———+————-+———+
 | id1    | id2        | name    |
 +———+————-+———+
 | 1234570 | 1234567.123 | gaopeng |
 +———+————-+———+
 1 row in set (0.00 sec)
虽然进行了四舍五入,但是不会有任何报错和警告,这是其标准决定的而不是数据库本生。
 可以看到 1234567.123 在 FLOAT 下被四舍五入为 1234570,而 DOUBLE 类型没有问题,那么我们
 直接从数据文件中提取数据。
 我还是使用了自己写的小工具 BCVIEW
 [root@Hadoop1 test]# bcview dname.ibd 16 127 40
 ******************************************************************
 This Tool Is Uesed For Find The Data In Binary format(Hexadecimal)
 Usage:./bcview file blocksize offset cnt-bytes!                 
 file: Is Your File Will To Find Data!                           
 blocksize: Is N kb Block.Eg: 8 Is 8 Kb Blocksize(Oracle)!       
                          Eg: 16 Is 16 Kb Blocksize(Innodb)!     
 offset:Is Every Block Offset Your Want Start!                                   
 cnt-bytes:Is After Offset,How Bytes Your Want Gets!                             
 Edtor QQ:22389860!                                               
 Used gcc version 4.1.2 20080704 (Red Hat 4.1.2-46)               
 ******************************************************************
 —-Current file size is :0.093750 Mb
 —-Current use set blockszie is 16 Kb
 current block:00000000–Offset:00127–cnt bytes:40–data is:00ffffffff0000000000010000000200260000000200260000000000000000ffffffff0000ffffff
 current block:00000001–Offset:00127–cnt bytes:40–data is:00000000000000000000000000000000000000000000000000000000000000000000000000000000
 current block:00000002–Offset:00127–cnt bytes:40–data is:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
 current block:00000003–Offset:00127–cnt bytes:40–data is:000001cc6d090000002d5679ab00000d0c011039b4964991ed7c1f87d6324167616f70656e670000
 current block:00000004–Offset:00127–cnt bytes:40–data is:00000000000000000000000000000000000000000000000000000000000000000000000000000000
 current block:00000005–Offset:00127–cnt bytes:40–data is:00000000000000000000000000000000000000000000000000000000000000000000000000000000

实际的数据是
000001cc6d09        rowid       
 0000002d5679ab      事物 ID         
 00000d0c0110        回滚指针         
39b49649            1234570     
 91ed7c1f87d63241    1234567.123 
 67616f70656e67      ‘gaopeng’   
关于如何得到数据的可以参考我的博文
http://blog.itpub.net/7728585/viewspace-2071787/
我们来分析下 float 的组成,因为 LINUX 属于小端,存储会是反向的
39b49649 实际是 4996b439

 49 01001001
 96 10010110
 b4 10110100
 39 00111001

    0    10010011    00101101011010000111001
符号位  指数位            尾数

10010011=147
这里需要减去 127
 147-127=20 为指数

 尾数 00101101011010000111001 需要加入一个 1.
如下 1.00101101011010000111001
如此我们需要将 1.00101101011010000111001
乘以 2 的 20 次方实际就是右移动 20 位
 为
100101101011010000111.001
整数部分
100101101011010000111=1234567 这里就是最后的数据 1234567
而显示的时候 1234567 又被四舍五入为 1234570

再来看 double

 91ed7c1f87d63241
实际为
4132d6871f7ced91

 0                          符号位
10000010011  1043 然后 1043-1023=20 级指数位
0010110101101000011100011111011111001110110110010001

1.0010110101101000011100011111011111001110110110010001
 100101101011010000111.00011111011111001110110110010001

整数部分为 100101101011010000111=1234567
关于小数部分的计算:
0*2^(0-1) 第一位
0*2^(0-2) 第二位
0*2^(0-3) 第三位
1*2^(0-4)=1/16 第四位
1*2^(0-5)=1/32 第五位
1*2^(0-6)=1/64 第六位
…..
及 0.123=0.0001111101111100 其额外的部分为无效数字

实际上数据是没有问题的。

本文永久更新链接地址:http://www.linuxidc.com/Linux/2016-04/130338.htm

正文完
星哥玩云-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2022-01-22发表,共计3739字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中