关于Float.parseFloat()的一点探讨
最近在解决线上的bug时,遇到一个问题。
第三方传过来的课程编码时4214410000,然而我们存进数据库的值却变成了4214409980。查遍了所有的代码都查不到有对这个值修改的代码。最后,通过打印日志的方法,找到了这个值改变的代码段。最终确定是Float.parseFloat(“4214410000”)改变了这个值。
老大告诉我这还不算解决问题,要查查为什么有的课程代码改变了,有的却没有改变,例如4211030020
。
然后,我就研究了jdk中Float.parseFloat()的源码。
在jdk 1.8中 Float.parseFloat()的实现是在FloatingDecimal.cass文件中,其中主要有两个方法,一个是readJavaFormatString()方法,一个是ASCIIToBinaryBuffer()。
第一个方法有以下几个功能
1.检验是否是空字符串
2.字符串是否是以'N' ,'I'开头,或者是否是八进制
3.给下一个方法提供四个参数,是否是负数,总长度,字符串数组,(总长度-字符串最后连续0的个数)
ASCIIToBinaryBuffer()获得以上四个参数后就开始生成float。
在看源码的时候,我发现4214410000生成的float步骤和4211030020不一致,导致不一致的原因是4214410000后面是连续的5个0。所以4214410000生成的float是421441.0* 10000.0得到的结果就是4.21440998E9。结果不是我们预想的整数,这是因为float的特性所决定的。《Effective Java》中已经讲出了这种问题,float/double不能停供完全精确的计算结果。这个原理其实很简单,float/int都是32bit(也就是一共有232个精确值),而int的范围是-231 ~ 231-1,而Float的最大值是3.4028235e+38,远大于231 - 1。而且,int只负责个数有限的整数,而浮点却要用来表示个数无穷的小数,显然力不从心。浮点精确值可以简单视作一个以0为中心的正态分布,绝对值越小(越接近0的地方),相邻两个精确值月密集。比如,最近的两个值可能只相差0.00000...几十个0...01,而最远的两个精确值,却差了2.028241E31。
到此,问题解决。以下贴上我的测试Float.parseFloat()的代码。
Float.parseFloat()的实现代码是我从jdk源码拷过来的,使用的是断点调试的方法。
public class Test { static float readJavaFormatString(String var0) throws NumberFormatException {
boolean var1 = false;
boolean var2 = false; try {
var0 = var0.trim();
int var5 = var0.length();
if (var5 == 0) {
throw new NumberFormatException("empty String");
} int var6 = 0;
switch(var0.charAt(var6)) {
case '-':
var1 = true;
case '+':
++var6;
var2 = true;
} char var4 = var0.charAt(var6); char[] var21 = new char[var5];
int var8 = 0;
boolean var9 = false;
int var10 = 0;
int var11 = 0; int var12;
for(var12 = 0; var6 < var5; ++var6) {
var4 = var0.charAt(var6);
if (var4 == '0') {
++var11;
} else {
if (var4 != '.') {
break;
} if (var9) {
throw new NumberFormatException("multiple points");
} var10 = var6;
if (var2) {
var10 = var6 - 1;
} var9 = true;
}
} for(; var6 < var5; ++var6) {
var4 = var0.charAt(var6);
if (var4 >= '1' && var4 <= '9') {
var21[var8++] = var4;
var12 = 0;
} else if (var4 == '0') {
var21[var8++] = var4;
++var12;
} else {
if (var4 != '.') {
break;
} if (var9) {
throw new NumberFormatException("multiple points");
} var10 = var6;
if (var2) {
var10 = var6 - 1;
} var9 = true;
}
} var8 -= var12;
boolean var13 = var8 == 0;
if (!var13 || var11 != 0) {
int var3;
if (var9) {
var3 = var10 - var11;
} else {
var3 = var8 + var12;
} if (var6 < var5 && ((var4 = var0.charAt(var6)) == 'e' || var4 == 'E')) {
byte var14 = 1;
int var15 = 0;
int var16 = 214748364;
boolean var17 = false;
++var6;
int var18;
switch(var0.charAt(var6)) {
case '-':
var14 = -1;
case '+':
++var6;
default:
var18 = var6;
} while(var6 < var5) {
if (var15 >= var16) {
var17 = true;
} var4 = var0.charAt(var6++);
if (var4 < '0' || var4 > '9') {
--var6;
break;
} var15 = var15 * 10 + (var4 - 48);
} int var19 = 324 + var8 + var12;
if (!var17 && var15 <= var19) {
var3 += var14 * var15;
} else {
var3 = var14 * var19;
} if (var6 == var18) {
throw new NumberFormatException("For input string: \"" + var0 + "\"");
}
} if (var6 >= var5 || var6 == var5 - 1 && (var0.charAt(var6) == 'f' || var0.charAt(var6) == 'F' || var0.charAt(var6) == 'd' || var0.charAt(var6) == 'D')) {
if (var13) {
return var1 ? -0.0f : 0.0f;
} return floatValue(var1,var3,var21,var8);
}
}
}catch (Exception e){
e.printStackTrace();
}
throw new NumberFormatException("For input string: \"" + var0 + "\"");
} private static final int SINGLE_MAX_SMALL_TEN;
private static final double[] SMALL_10_POW = new double[]{1.0D, 10.0D, 100.0D, 1000.0D, 10000.0D, 100000.0D, 1000000.0D, 1.0E7D, 1.0E8D, 1.0E9D, 1.0E10D, 1.0E11D, 1.0E12D, 1.0E13D, 1.0E14D, 1.0E15D, 1.0E16D, 1.0E17D, 1.0E18D, 1.0E19D, 1.0E20D, 1.0E21D, 1.0E22D};
private static final float[] SINGLE_SMALL_10_POW = new float[]{1.0F, 10.0F, 100.0F, 1000.0F, 10000.0F, 100000.0F, 1000000.0F, 1.0E7F, 1.0E8F, 1.0E9F, 1.0E10F};
private static final int MAX_SMALL_TEN;
private static final double[] BIG_10_POW = new double[]{1.0E16D, 1.0E32D, 1.0E64D, 1.0E128D, 1.0E256D};
private static final double[] TINY_10_POW = new double[]{1.0E-16D, 1.0E-32D, 1.0E-64D, 1.0E-128D, 1.0E-256D};
static {
MAX_SMALL_TEN = SMALL_10_POW.length - 1;
SINGLE_MAX_SMALL_TEN = SINGLE_SMALL_10_POW.length - 1;
}
static float floatValue(Boolean isNegative,int decExponent,char[] digits,int nDigits ) {
int var1 = Math.min(nDigits, 8);
int var2 = digits[0] - 48; for(int var3 = 1; var3 < var1; ++var3) {
var2 = var2 * 10 + digits[var3] - 48;
} float var27 = (float)var2;
int var4 = decExponent - var1;
int var7;
if (nDigits <= 7) {
if (var4 == 0 || var27 == 0.0F) {
return isNegative ? -var27 : var27;
} if (var4 >= 0) {
if (var4 <= SINGLE_MAX_SMALL_TEN) {
var27 *= SINGLE_SMALL_10_POW[var4];
return isNegative ? -var27 : var27;
} int var5 = 7 - var1;
if (var4 <= SINGLE_MAX_SMALL_TEN + var5) {
var27 *= SINGLE_SMALL_10_POW[var5];
var27 *= SINGLE_SMALL_10_POW[var4 - var5];
return isNegative ? -var27 : var27;
}
} else if (var4 >= -SINGLE_MAX_SMALL_TEN) {
var27 /= SINGLE_SMALL_10_POW[-var4];
return isNegative ? -var27 : var27;
}
} else if (decExponent >= nDigits && nDigits + decExponent <= 15) {
long var29 = (long)var2; for(var7 = var1; var7 < nDigits; ++var7) {
var29 = var29 * 10L + (long)(digits[var7] - 48);
} double var31 = (double)var29;
var4 = decExponent - nDigits;
var31 *= SMALL_10_POW[var4];
var27 = (float)var31;
return isNegative ? -var27 : var27;
} double var28 = (double)var27;
if (var4 > 0) {
if (decExponent > 39) {
return isNegative ? -1.0F: 1.0F ;
} if ((var4 & 15) != 0) {
var28 *= SMALL_10_POW[var4 & 15];
} if ((var4 >>= 4) != 0) {
for(var7 = 0; var4 > 0; var4 >>= 1) {
if ((var4 & 1) != 0) {
var28 *= BIG_10_POW[var7];
} ++var7;
}
}
} else if (var4 < 0) {
var4 = -var4;
if (decExponent < -46) {
return isNegative ? -0.0F : 0.0F;
} if ((var4 & 15) != 0) {
var28 /= SMALL_10_POW[var4 & 15];
} if ((var4 >>= 4) != 0) {
for(var7 = 0; var4 > 0; var4 >>= 1) {
if ((var4 & 1) != 0) {
var28 *= TINY_10_POW[var7];
} ++var7;
}
}
} var27 = Math.max(1.4E-45F, Math.min(3.4028235E38F, (float)var28));
if (nDigits > 200) {
nDigits = 201;
digits[200] = '1';
} FDBigInteger var30 = new FDBigInteger((long)var2,digits, var1,nDigits);
var4 = decExponent - nDigits;
int var8 = Float.floatToRawIntBits(var27);
int var9 = Math.max(0, -var4);
int var10 = Math.max(0, var4);
var30 = var30.multByPow52(var10, 0);
var30.makeImmutable();
FDBigInteger var11 = null;
int var12 = 0; do {
int var13 = var8 >>> 23;
int var14 = var8 & 8388607;
int var15;
int var16;
if (var13 > 0) {
var14 |= 8388608;
} else {
assert var14 != 0 : var14; var15 = Integer.numberOfLeadingZeros(var14);
var16 = var15 - 8;
var14 <<= var16;
var13 = 1 - var16;
} var13 -= 127;
var15 = Integer.numberOfTrailingZeros(var14);
var14 >>>= var15;
var16 = var13 - 23 + var15;
int var17 = 24 - var15;
int var18 = var9;
int var19 = var10;
if (var16 >= 0) {
var18 = var9 + var16;
} else {
var19 = var10 - var16;
} int var20 = var18;
int var21;
if (var13 <= -127) {
var21 = var13 + var15 + 127;
} else {
var21 = 1 + var15;
} var18 += var21;
var19 += var21;
int var22 = Math.min(var18, Math.min(var19, var20));
var18 -= var22;
var19 -= var22;
var20 -= var22;
FDBigInteger var23 = FDBigInteger.valueOfMulPow52((long)var14, var9, var18);
if (var11 == null || var12 != var19) {
var11 = var30.leftShift(var19);
var12 = var19;
} FDBigInteger var24;
int var25;
boolean var26;
if ((var25 = var23.cmp(var11)) > 0) {
var26 = true;
var24 = var23.leftInplaceSub(var11);
if (var17 == 1 && var16 > -126) {
--var20;
if (var20 < 0) {
var20 = 0;
var24 = var24.leftShift(1);
}
}
} else {
if (var25 >= 0) {
break;
} var26 = false;
var24 = var11.rightInplaceSub(var23);
} var25 = var24.cmpPow52(var9, var20);
if (var25 < 0) {
break;
} if (var25 == 0) {
if ((var8 & 1) != 0) {
var8 += var26 ? -1 : 1;
}
break;
} var8 += var26 ? -1 : 1;
} while(var8 != 0 && var8 != 2139095040); if (isNegative) {
var8 |= -2147483648;
} return Float.intBitsToFloat(var8);
} public static void main(String args[]) {
String ss = "4214410000";
String cc = "4211030020";
readJavaFormatString(ss);
readJavaFormatString(cc);
} }
关于Float.parseFloat()的一点探讨的更多相关文章
- CSS display:inline和float:left两者区别探讨
本文和大家重点讨论一下CSS display:inline和float:left两者的区别,CSS display是指显示状态,inline表示内联,特点是紧贴着前一个内联元素,通常默认的内联元素有 ...
- String转double或者float会有精度丢失的问题
float [] value=new float[5]; value[0]=Float.parseFloat(rs.getString(1)); value[1]=Float.parseFloat(r ...
- Android 在xml中配置 float 和 integer 值
一.float的配置方法 andriod 默认不支持float型的设置,在values 下的新建floats.xml 文件,在内部添加如下代码: <resources> <item ...
- java一点内容
1.JAVA有哪些基本数据类型 String是不是基本数据类型 Java语言提供了八种基本类型: 六种数字类型(四个整数型,两个浮点型) 字节型byte 8位 短整型short 16位 整型int 3 ...
- String转float
float mTotalhour = Float.parseFloat(mTotalHourEt.getText().toString().trim());
- 数据库中float类型字段,转化到前端显示,统一保留两位小数
客户的一个需求,mybatis查询到的数据库的数据进行转换,采用TypeHandler<T>的方式.float保留两位精度可以采用DecimalFormat 直接贴上最终的解决代码(事情没 ...
- Java不同类型字符转换String/int/Float/////
1.int & String int i=5678;String s=""; int->String: s=i+"";或 s=String.val ...
- float失效的情况
前言:在最近的笔试中,两次碰到类似的问题,什么情况下float会失效?我目前知道的有2种: 1)display:none: 2)position:absolute.fixed. (1)display: ...
- DecimalFormat 四舍五入Float类型的坑
今天又踩了一个坑,使用DecimalFormat来完毕四舍五入.可是传入的是float类型,几轮測试才发现一个问题,传入的float会被转为double类型.大家都知道float是4位,double是 ...
随机推荐
- Web 安全之 XSS 攻击与防御
前言 黑客,相信大家对这一名词并不陌生,黑客们往往会利用 Web 应用程序的漏洞来攻击咱们的系统.开放式 Web 应用程序安全项目(OWASP, Open Web Application Securi ...
- 改变一下主要发博的方向吧...转scratch!
因为expression2实在是没什么好说的,BUI,水滴鱼大佬还有其他贴吧上的大佬,实在是多得不行,我一个小人物也说不了什么,然而scratch我却可以多发发脚本,思路,美工啊等等.所以以后我就主要 ...
- Hadoop MapReduce2.0(Yarn)
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/cqboy1991/article/details/25056283 MapReduce2.0(Yar ...
- 【代码问题】MatConvNet+VS2017编译找不到cl.exe错误
用vl_compilenn做普通的CPU编译报错: 'cl.exe' 不是内部或外部命令,也不是可运行的程序 或批处理文件. 错误使用 vl_compilenn>check_clpath (li ...
- 【rabbitmq】RabbitMQ 集群与网络分区
网络分区(network partitions) 官网-网络分区 网络设备故障导致的网络分裂.比如,存在A\B\C\D\E五个节点,A\B处于同一子网,B\C\D处于另外一子网,中间通过交换机相连.若 ...
- final link failed: Nonrepresentable section on output
编译live555的时候遇到了这个问题,前面的编译没有问题,是在链接的时候出现的,在网上搜索说是缺少 libstdc++ 库.于是,安装之 #sudo apt-get install libstdc ...
- Lubuntu下安装Python3.6
Lubuntu下系统自带的Python版本是2.X,由于开发环境要求Python3,于是我们安装Python3.6 1.在终端输入以下命令: sudo add-apt-repository ppa:j ...
- IIS发布ASP.NET Core
安装IIS.程序和功能--程序卸载--启用或关闭Windows功能 安装.NET Core SDK和Runtime.下载网址 https://www.microsoft.com/net/downloa ...
- Google SketchUp Cookbook: (Chapter 4) Advanced Intersect and Follow Me Techniques
软件环境 SketchUp Pro 2018 参考书籍 Google SketchUp Cookbook Intersect 工具经常与 Follow Me 工具一起使用,以创建复杂的 3D 物体. ...
- axublogcms1.1.0 Getshell
axublogcms1.1.0 Getshell 代码执行漏洞 现在最新版是1.1.0 今天重新审计了下 axublogcms1.0.6 ,发现一处计较鸡肋的漏洞,因为并不是只有1.0.6版本存在 ...