做一个网站赚钱吗菏泽定制网站建设推广
news/
2025/9/23 1:58:29/
文章来源:
做一个网站赚钱吗,菏泽定制网站建设推广,南京高新区网站建设,做商城网站需要多大的服务器前言
前段时间开发新的微信小程序#xff0c;借此机会将老掉牙的支付模块重构#xff0c;并且支持现金支付#xff08;之前都是虚拟币支付#xff09;#xff0c;在重构期间遇到计算上的一些精度问题#xff0c;虽然数额影响非常小但是影响比较大#xff0c;我觉得有必…前言
前段时间开发新的微信小程序借此机会将老掉牙的支付模块重构并且支持现金支付之前都是虚拟币支付在重构期间遇到计算上的一些精度问题虽然数额影响非常小但是影响比较大我觉得有必要总结以下遇到的一些问题并且解决弄清楚他的原来因此有下文。
先看几个现象
当我们程序中涉及到一些double或者float类型的数据并且精度要求比较高小数点位数比较多的时候可能会出现一些非常奇葩的问题我下面针对遇到的一些问题给出几个说明案例
条件判断异常
//比较特殊的案例
System.out.println(1f 0.9999999f); //false
System.out.println(1f 0.99999999f); //true数据转换异常
float f 0.6f;
double d1 0.6d;
double d2 f;
System.out.println((d1 d2) f d2);//false 0.6 基本运算异常 System.out.println( 0.2 0.7 ); //0.8999999999999999数据自增异常 float f1 8455263f;for (int i 0; i 10; i) {System.out.println(f1);f1;}
//8455263.0
//8455264.0
//8455265.0
//8455266.0
//8455267.0
//8455268.0
//8455269.0
//8455270.0
//8455271.0
//8455272.0float f2 84552631f;for (int i 0; i 10; i) {System.out.println(f2);f2;}
//8.4552632E7
//8.4552632E7
//8.4552632E7
//8.4552632E7
//8.4552632E7
//8.4552632E7
//8.4552632E7
//8.4552632E7
//8.4552632E7
//8.4552632E7Java中浮点类型精度问题
要搞清除还是得从java的double和float类型来入手我们都知道计算机只认识二进制的01那么在double和float中有整数部分小数部分如此说来那么应该会有一定的方式将小数转为计算机认识的01 组合这中方法是定义的一个转换标准其实而Java中浮点数采用的是IEEE 754标准
IEEE745 标准
IEEE 745 是IEEE二进制浮点数算数标准Standard for Floating-Point Arthmetic的标准编号等同一个国际标准ISO之类是美国哪家公司订的这个标准定义来表示浮点数的格式包括负零-0与反常值denormal number一些特殊数值例如无穷inf非数值NaN以及一些数值的“浮点数运算子”它知名来四种数值修约规则和五种例外状况。还有要了解的可以去JDK官网
浮点数的组成结构
我们学习计算机组成原理的时候应该学过的Java中表示小数的时候有三个组成部分 符号位 S阶码部分 E尾数部分 M 这三个纬度的信息一个浮点数表示就可以完全确认下来如下图所示的存储结构 符号位部分 S 0 表示正数 1 表示负数阶码部分E 只整数部分 对于float型浮点数指数部分8 位考虑可正负因此可以表示的指数范围是-127128对于double类型浮点数指数部分11 为可正负因此可以表示的指数范围是-12031024 尾数部分 M 对于float类型来说尾数23 为计算成十进制就是223 8388608所以十进制精度只有67位对于double类型来说尾数部分52位计算成十进制就是2524503599627370496所以十进制的精度是1516位 以上几个都是官方的数据
总结
浮点数float和double在内存中是按照科学计数法来存储的取值范围是由指数的位数来决定的精度是由尾数的位数来决定的。
浮点数精度/位数符号S指数E扩展范围 (指数的取值范围)最大/小值(取值范围)尾数位M尾数取值范围(精度)float32bit 单精度1bit(0正1负)8bit-27 ~ 27-1(-128~127)2127(1038级别的数)23bit8388608,7位,精度为6~7位double64bit双精度1bit(0正1负)11bits-210 ~ 210-1(-1024~1023)21023(10308级别的数)52bit45035_99627_37049_6,16位,精度为15~16位
浮点数和二进制数互相转化
十进制浮点数如何用二进制表示
计算过程小数部分将小数部分乘以2取出结果中整数部分作为二进制表示的第一位大于等于1为1小于1 为0然后在将小数部分乘以2得到整数部分作为二进制表示第二位…依次类推知道小数部分位0.特殊情况永远都不会位0:小数部分循环出现无法停止则用优先的二进制位无法表示这个小数这也是在编程语言中小数位出现误差的原因。我们用如下的案例来说明这个过程10.6:
0.6*21.2 ---- 1
0.2*20.4 ---- 0
0.4*20.8 ---- 0
0.8*21.6 ---- 1
0.6*21.2 ---- 1
0.2*20.4 ---- 0
.
.
.
0.6*21.2 ---- 1
0.2*20.4 ---- 0以上我们可以发现0.6 是一个无法精确表示的一个数值用二进制表示1001 1001 1001 1001 …那10.6 的二进制我们可以表示如下1010.1001 1001 1001 …
二进制浮点数如何转为十进制
计算过程从左到右v[i]*2(-i), i为从左到右的indexv[i]为该位的值直接看例子如下10.6 的二进制1010.1001 1001 1001从小数点位为基准如下0 * 20 1 * 21 0 * 2 2 1 * 23 0208//整数部分1 * 2-1 0 * 2-2 0 * 2-3 1 * 2-4 1 * 2-5 0 * 2-6 0 * 2-7 1 * 2-8 … 0.50.0625 0.03125 ≈ 0.6 // 小数部分
问题解答
我们通过开始的案例还有之前关于doublefloat这部分的分析我们来解答一下最开始的哪些问题是怎么出现的
float类型赋值给double类型变量出现精度问题
因为float的尾数23为double尾数52位所以float类型中保存的0.6 的二进制转成double二进制的时候低位的二进制自动变成0 与用double类型保存的0.6的二进制是不一样的所以出问题来如下图来解释
float 类型的0.6f
1001 1001 1001 1001 1001 100
double类型的d1 0.6d
1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001
将float类型f 赋值给double类型的d2后d2 的实际数据位
1001 1001 1001 1001 1001 1000 0000 0000 0000 0000 0000 0000 0000如上如果用d2 和d1 比较他们肯定是不相等的
第一个案例分析
System.out.println( 1f 0.99999999f );这个结果是true因为计算机无法区分这个两个的二进制数我们也来推到一些他们的二进制表示
1.0十进制↓
00111111 10000000 00000000 00000000二进制↓
0x3F800000十六进制0.99999999十进制↓
00111111 10000000 00000000 00000000二进制↓
0x3F800000十六进制0.9999999十进制↓
00111111 01111111 11111111 11111110二进制↓
0x3F7FFFFE十六进制如上这第一个和第二个二进制数是一样的第三个是不一样的只是因为上面的0.99999999f8个9 明显超过来float类型的精度范围凑巧和1 是一样的就出现这种问题。
浮点计算
Java当中默认声明的小数是double类型的其默认后缀d或D可以省略如果要声明为float类型需显示添加后缀f或F我们尽量用BigDecial来计算
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/911057.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!