正由于用浮点数表示小数可能会有不精确的状况,在一些状况下咱们必须保证小数是精确的,因此设计MySQL的大叔们提出一种称之为定点数的数据类型,它也是存储小数的一种方式:bash
其中:spa
注意是有效数字个数,比方说对于小数**-2.3来讲有效数字个数就是2,对于小数0.9来讲有效数字个数就是1**。设计
这个好理解,小数点后有几个十进制数字,D的值就是什么。code
举个例子看一下,设置了M和D的单精度浮点数的取值范围的变化:cdn
能够看到,在D相同的状况下,M越大,该类型的取值范围越大;在M相同的状况下,D越大,该类型的取值范围越小。固然,M和D的取值也不是无限大的,M的取值范围是1~255,D的取值范围是0~30,并且D的值必须不大于M。M和D都是可选的,若是咱们省略了它们,那它们的值按照机器支持的最大值来存储。blog
咱们说定点数是一种精确的小数,为了达到精确的目的咱们就不能把它转换成二进制小数以后再存储(由于有不少十进制小数转为二进制小数后须要进行舍入操做,致使二进制小数表示的数值是不精确的)。其实转念一想,所谓的小数只是把两个十进制整数用小数点分割开来而已,咱们只要把小数点左右的两个十进制整数给存储起来,那不就是精确的了么。比方说对于十进制小数2.38来讲,咱们能够把这个小数的小数点左右的两个整数,也就是2和38分别保存起来,那么不就至关于保存了一个精确的小数么,这波操做是否是很6。it
固然事情并无这么简单,对于给定M、D值的**DECIMAL(M, D)类型,好比DEMCIMAL(16, 4)**来讲:io
从图中能够看出,若是不足9个十进制位,也会被划分红一组。class
因此DECIMAL(16, 4)共须要占用8个字节的存储空间大小,这8个字节由下边3个部分组成:数据类型
这些步骤看的有一丢丢懵逼吧,别着急,举个例子就都清楚了。比方说咱们使用定点数类型DECIMAL(16, 4)来存储十进制小数1234567890.1234,这个小数会被划分红3个部分:
1 234567890 1234
复制代码
也就是:
而后将每一组中的十进制数字转换成对应的二进制数字:
00000000 00000001
复制代码
二进制看起来太难受,咱们仍是转换成对应的十六进制看一下:
0x0001
复制代码
0x0DFB38D2
复制代码
0x04D2
复制代码
因此将这些十六进制数字连起来以后就是:
0x00010DFB38D204D2
复制代码
最后还要将这个结果的最高位设置为1,因此最终十进制小数1234567890.1234使用定点数类型**DECIMAL(16, 4)**存储时共占用8个字节,具体内容为:
0x80010DFB38D204D2
复制代码
有的朋友会问,若是咱们想使用定点数类型DECIMAL(16, 4)存储一个负数怎么办,比方说-1234567890.1234,这时只须要将0x80010DFB38D204D2中的每个比特位都执行一个取反操做就好,也就是获得下边这个结果:
0x7FFEF204C72DFB2D
复制代码
从上边的叙述中咱们能够知道,对于DECIMAL(M, D)类型来讲,给定的M和D的值不一样,所需的存储空间大小也不一样。能够看到,与浮点数相比,定点数须要更多的空间来存储数据,因此若是不是在某些须要存储精确小数的场景下,通常的小数用浮点数表示就足够了。
对于定点数类型DECIMAL(M, D)来讲,M和D都是可选的,默认的M的值是10,默认的D的值是0,也就是说下列等式是成立的:
DECIMAL = DECIMAL(10) = DECIMAL(10, 0)
DECIMAL(n) = DECIMAL(n, 0)
复制代码
另外M的范围是1~65,D的范围是0~30,且D的值不能超过M。