重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
在公司项目中看到关于钱的数据在接口展示、添加修改的各种情况下结构体中相应字段用的都是string类型。觉得不太合理,因此查阅了一些资料,整理如下。
创新互联长期为1000多家客户提供的网站建设服务,团队从业经验10年,关注不同地域、不同群体,并针对不同对象提供差异化的产品和服务;打造开放共赢平台,与合作伙伴共同营造健康的互联网生态环境。为大方企业提供专业的成都网站制作、做网站,大方网站改版等技术服务。拥有10年丰富建站经验和众多成功案例,为您定制开发。
在网上搜到一篇博客:
在程序计算中涉及到钱的时候,为什么要用Decimal而不是Float
博客中介绍,如果用float类型再转为decimal类型时会造成精度丢失。转为string后再转为decimal则可以解决问题,保证精度。看着好像是很完美的回答了我想要了解的问题,但仔细一看用的语言是python,于是我便亲自试了下:
结果确实如此,但看版本是2.7,我怀疑是不是python2.7版本落后,因此存在问题,于是又换了python3,再次测试:
结论依然是一样。好吧,证实了,对于python确实应该先转为string再转为decimal。
但是,python是这样,难道go也是这样吗,于是我又开始了进一步测试:
go中decimal使用第三方库
这里是直接用float64转为decimal,并没有通过string中转,结果输出如下:
乍一看,看着好像是精度丢失了似的,但是对比后我们发现,float64和decimal前后都是一致的,也就是说float64转为decimal之后,保持了原样。那些看起来小数点后位数很多的结果,是因为float64浮点类型计算产生的问题,跟转换并没有关系。
为了验证这一结论,我又写了下面的测试:
不使用浮点类型相加,而用decimal类型相加,这样输出结果果然没问题了:
因此我们可以得出结论:对于go语言,在把float转换为decimal类型时,并不需要像python一样通过string中转,也依然可以保持精度。进一步,我们也可以想到上面的问题,对于钱,在结构体字段中,我们完全可以直接使用float类型,并不需要用string类型。而且好处时,使用float数值类型,无论对于前端还是后端,在进行数值范围验证的时候,会更方便,不必把string转为float后再验证了。
上面提到了decimal包,我们这里简单看下,里面的常用的方法:
定义decimal的几种方式:
decimal数值运算
比较:
我们再看下浮点精度运算不准确的原因,这篇文章讲解的比较细
浮点精度(float、double)运算不精确的原因
精度运算不准确这是为什么呢?我们接下来就需要从计算机所有数据的表现形式二进制说起了。如果大家很了解二进制与十进制的相互转换,那么就能轻易的知道精度运算不准确的问题原因是什么了。
接下来我们看一个简单的例子 2.1 这个十进制数转成二进制是什么样子的。
落入无限循环结果为 10.0001100110011........ , 我们的计算机在存储小数时肯定是有长度限制的,所以会进行截取部分小数进行存储,从而导致计算机存储的数值只能是个大概的值,而不是精确的值。从这里看出来我们的计算机根本就无法使用二进制来精确的表示 2.1 这个十进制数字的值,连表示都无法精确表示出来,计算肯定是会出现问题的。
1、为什么数值表示用decimal 不用double
2、在程序计算中涉及到钱的时候,为什么要用Decimal而不是Float
3、MySQL数据类型DECIMAL用法
4、浮点精度(float、double)运算不精确的原因
例如:把十六进制的04271544和0209FE83转换成二进制。方法:首先把十六进制数04271544中的每一位数转换为二进制数,每个数要分四位,不足四位的前面加零,请看下面演示:
0 0000
4 0100
2 0010
7 0111
1 0001
5 0101
4 0100
4 0100
将得出四位二进制数串连起来就是结果了
-1的二进制是1111 1111,不是1000 0001喔,负数的二进制表示为其原码的反码再加1,
正数的反码跟原码不变,而负数的反码除符号位外其他位取反
-1的原码是1000 0001,所以反码为1111 1110,最后在加1即1111 1111
如果二进制1000 0001是一个有符号位的8位数据,那么最高位为符号位,1为负数0为正数
那反过来二进制1000 0001表示成十进制就是减1在取反,
1000 0001 - 1=1000 0000
除符号位取反后为1111 1111即-127
fmt.Sprint()的参数为interface,可以将任意的类型转为string
函数原型:func FormatInt(i int64, base int) string
参数说明:base为进制数
base为十和十六进制数的区别的举例