Python float 和 decimal
、
Python float 和 decimal
这里我想记录的是 Python 的 Decimal 类型和 float 的转换问题。
Python 的 Decimal 支持从 str 和 float 进行转换,比如
from decimal import Decimal
f = 3.1666666666666666
Decimal(str(f))
Decimal('3.16666666667')
Decimal(f)
Decimal('3.166666666666666518636930049979127943515777587890625')
Decimal.from_float(f)
Decimal('3.166666666666666518636930049979127943515777587890625')
比如很明显能看出一个数通过 str 或 float 直接转换都会和真正输入的不一样,这个问题是由于小数以二进制形式在计算机内表达的问题。除此之外,可以很明显看到 float 转换到 str 是经过 round 的,具体可以参考 converting-a-float-to-a-string-without-rounding-it ,最终说的都是浮点用二进制表示的问题。
所以在应对精度非常高的浮点的时候,记得一定要保留指定位的小数,尤其是在数据库设计时如果需要 Decimal 类型的,记得指定具体的精度来使数据在数据库和 Python 中都能保持一致。
MySQL设计浮点类型的字段用decimal的好处与坏处
在后端开发中,数据库MySQL我以前经常使用float和double来存储浮点型数据,但现在发现很多的精度丢失问题。
现在来看看他们的区别
-
float 类型用于表示单精度浮点数值,而double类型用于表示双精度浮点数值,float 和 double 都是浮点型,而decimal 是定点型;
-
MySQL 浮点型和定点型可以用类型名称后加(M,D)来表示,M表示该值的总共长度,D表示小数点后面的长度,M和D又称为精度和标度,如float(7,4)的 可显示为-999.9999,MySQL保存值时进行四舍五入,如果插入999.00009,则结果为999.0001。
-
FLOAT 和 DOUBLE 在不指 定精度时,默认会按照实际的精度来显示,而 DECIMAL 在不指定精度时,默认整数为10,小数为0。
-
DECIMAL和NUMERIC值作为字符串存储,而不是作为二进制浮点数,以便保存那些值的小数精度
decimal的格式:decimal(M,D)中D代表存储的小数位的长度,而M代表的是整数位加小数位的总长度
看看区别
建立一张表,存着三种不同的浮点型字段,各自插入相同的数据1234567.23
imageinsert INTO fudianxing VALUE (1234567.23,1234567.23,1234567.23);
image很明显float会出错,而double和decimal在这里没错误,decimal类型在更大的范围内的精度肯定会比double高。
那就来修改表结构,插入更大的值。
imageinsert INTO fudianxing VALUE (1234567.23,12345671111111111111111.23,12345671111111111111111.23);
image这里看出decimal类型更加的好用了吧,所以大家搞起来。
先总结几个好处和缺点
float和double都是采用二进制的格式存储的,decimal在存储时采用字符串存储,能够很好地保留小数地精度。
但缺点是向decimal类型字段插入超过定义的数字会省略后几位的数字,并输出警告:(数据库版本为10.1.37-MariaDB)
比如decimal(5,2),插入222.22时是正常的;插入222.222时则省略最后一位,插入222.22;插入222.225时,就会四舍五入插入222.23;
如上定义,当插入一个四位数4396的数字时就会插入一个最大值999.99,并输出警告,不会报错;
当插入整数888时就会显示888,并不会显示888.00,这就比其他两个浮点型好。
如上是decimal的定义,我觉得是一个缺点吧,因为他们居然都插入成功了,并且以边界值来处理,但严格意义上来说并不算缺点,算是一个对错误的兼容。
现在就来说优点:
-
数值以字符串的形式保存,存储了一个准确(精确)的数字表达法,不存储值的近似值。
这种方法很好地处理float和double类型都会发生的错误,因为他们都是以二进制存储的,所以有一定的误差。一个字符用于值的每一位、小数点 -
decimal有更多的位数保存数值
float:浮点型,含字节数为4,32bit,数值范围为-3.4E38~3.4E38(7个有效位)
double:双精度实型,含字节数为8,64bit数值范围-1.7E308~1.7E308(15个有效位)
decimal:数字型,128bit,不存在精度损失,常用于银行帐目计算。(28个有效位)
decimal(a,b)参数说明
a指定指定小数点左边和右边可以存储的十进制数字的最大个数,最大精度38。
b指定小数点右边可以存储的十进制数字的最大个数。小数位数必须是从 0 到 a之间的值。默认小数位数是 0。 -
decimal 数据类型最多可存储 38 个数字,所有数字都能够放到小数点的右边。
总结:数值用decimal就对了,因为数字迟早会变大的。