最近在解决线上的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()的一点探讨的更多相关文章

  1. CSS display:inline和float:left两者区别探讨

     本文和大家重点讨论一下CSS display:inline和float:left两者的区别,CSS display是指显示状态,inline表示内联,特点是紧贴着前一个内联元素,通常默认的内联元素有 ...

  2. String转double或者float会有精度丢失的问题

    float [] value=new float[5]; value[0]=Float.parseFloat(rs.getString(1)); value[1]=Float.parseFloat(r ...

  3. Android 在xml中配置 float 和 integer 值

    一.float的配置方法 andriod 默认不支持float型的设置,在values 下的新建floats.xml 文件,在内部添加如下代码: <resources> <item ...

  4. java一点内容

    1.JAVA有哪些基本数据类型 String是不是基本数据类型 Java语言提供了八种基本类型: 六种数字类型(四个整数型,两个浮点型) 字节型byte 8位 短整型short 16位 整型int 3 ...

  5. String转float

    float mTotalhour = Float.parseFloat(mTotalHourEt.getText().toString().trim());

  6. 数据库中float类型字段,转化到前端显示,统一保留两位小数

    客户的一个需求,mybatis查询到的数据库的数据进行转换,采用TypeHandler<T>的方式.float保留两位精度可以采用DecimalFormat 直接贴上最终的解决代码(事情没 ...

  7. Java不同类型字符转换String/int/Float/////

    1.int & String int i=5678;String s=""; int->String: s=i+"";或 s=String.val ...

  8. float失效的情况

    前言:在最近的笔试中,两次碰到类似的问题,什么情况下float会失效?我目前知道的有2种: 1)display:none: 2)position:absolute.fixed. (1)display: ...

  9. DecimalFormat 四舍五入Float类型的坑

    今天又踩了一个坑,使用DecimalFormat来完毕四舍五入.可是传入的是float类型,几轮測试才发现一个问题,传入的float会被转为double类型.大家都知道float是4位,double是 ...

随机推荐

  1. Web 安全之 XSS 攻击与防御

    前言 黑客,相信大家对这一名词并不陌生,黑客们往往会利用 Web 应用程序的漏洞来攻击咱们的系统.开放式 Web 应用程序安全项目(OWASP, Open Web Application Securi ...

  2. 改变一下主要发博的方向吧...转scratch!

    因为expression2实在是没什么好说的,BUI,水滴鱼大佬还有其他贴吧上的大佬,实在是多得不行,我一个小人物也说不了什么,然而scratch我却可以多发发脚本,思路,美工啊等等.所以以后我就主要 ...

  3. Hadoop MapReduce2.0(Yarn)

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/cqboy1991/article/details/25056283 MapReduce2.0(Yar ...

  4. 【代码问题】MatConvNet+VS2017编译找不到cl.exe错误

    用vl_compilenn做普通的CPU编译报错: 'cl.exe' 不是内部或外部命令,也不是可运行的程序 或批处理文件. 错误使用 vl_compilenn>check_clpath (li ...

  5. 【rabbitmq】RabbitMQ 集群与网络分区

    网络分区(network partitions) 官网-网络分区 网络设备故障导致的网络分裂.比如,存在A\B\C\D\E五个节点,A\B处于同一子网,B\C\D处于另外一子网,中间通过交换机相连.若 ...

  6. final link failed: Nonrepresentable section on output

    编译live555的时候遇到了这个问题,前面的编译没有问题,是在链接的时候出现的,在网上搜索说是缺少 libstdc++ 库.于是,安装之 #sudo apt-get install  libstdc ...

  7. Lubuntu下安装Python3.6

    Lubuntu下系统自带的Python版本是2.X,由于开发环境要求Python3,于是我们安装Python3.6 1.在终端输入以下命令: sudo add-apt-repository ppa:j ...

  8. IIS发布ASP.NET Core

    安装IIS.程序和功能--程序卸载--启用或关闭Windows功能 安装.NET Core SDK和Runtime.下载网址 https://www.microsoft.com/net/downloa ...

  9. Google SketchUp Cookbook: (Chapter 4) Advanced Intersect and Follow Me Techniques

    软件环境 SketchUp Pro 2018 参考书籍 Google SketchUp Cookbook Intersect 工具经常与 Follow Me 工具一起使用,以创建复杂的 3D 物体. ...

  10. axublogcms1.1.0 Getshell

    axublogcms1.1.0 Getshell 代码执行漏洞 现在最新版是1.1.0   今天重新审计了下 axublogcms1.0.6 ,发现一处计较鸡肋的漏洞,因为并不是只有1.0.6版本存在 ...