最近在做支付相关模块的业务,数据库字段却使用的是double类型,其实也行,只要计算不在sql语句中进行,也是没有问题的。

预先的类属性设置的是Double类型,自己算的时候发现小数相加会出现损失精度的情况

如下情形

    @Test
public void testDouble(){
Double [] arr = {39.9d,50d,198d,39.9d};
Double verify = 0d;
for (Double aDouble : arr) {
verify += aDouble ;
}
System.out.println(verify);
}

输出的结果是:327.79999999999995  理应为:328

待着疑惑试了下js

一看是一个效果,精度都会缺失。百度了下,解释如下

产生原因:
    计算机并不能识别除了二进制数据以外的任何数据,无论我们使用何种编程语言,在何种编译环境下工作,都要先把源程序翻译成二进制的机器码后才能被计算机识别。
    而在存储浮点型数据时,会分为三部分进行存储:
  1. 符号位(Sign): 0代表正,1代表为负
  2. 指数位(Exponent):用于存储科学计数法中的指数数据,并且采用移位存储
  3. 尾数部分(Mantissa):尾数部分
    其中前两位分别为实数符号位和指数符号位,于是存储结构实际为如下:

                    31                  30            29----23        22----0         

               实数符号位    指数符号位    指数位      有效数位

但是,在将十进制浮点数转换为二进制浮点数时,小数的二进制有时也是不可能精确的,就如同十进制不能准确表示1/3,二进制也无法准确表示1/10,而double类型存储尾数部分最多只能存储52位,于是,计算机在存储该浮点型数据时,便出现了精度丢失。

  例如,11.9的内存存储大约为:1011. 1110011001100110011001100...

而在进行浮点类数据计算的时候,浮点参与计算,会左移或右移n位,直到小数点移动到第一个有效数字的右边。于是11.9在转化为二进制后 小数点左移3位,就得到1. 011 11100110011001100110(精度丢失2)

于是最终浮点型运算出现了精度丢失误差。

解决方式,java中可以使用 BigDecimal 来解决

    @Test
public void test3(){
System.out.println(0.11+2001299.32);//非精确的输出
BigDecimal bigDecimal1 = new BigDecimal(Double.toString(0.11));
BigDecimal bigDecimal2 = new BigDecimal(Double.toString(2001299.32));
System.out.println(bigDecimal1.add(bigDecimal2));//精确的输出
}

这种方式可以解决,并且很完美,但是还有一种方式比较容易些,毕竟是金额,小数位只有两位,可以先将其扩大100倍,再进行计算,计算完毕之后再除100,也可以解决(这么不要脸的方式也只有我这么low的程序员使用了),惭愧,出错了。

在计算的过程总遇到double转int的情况,总结了下实现的方式

    Double d = 1.7d;

    @Test
public void test1(){
// 这样会报错,因为double转换为字符串之后有.
System.out.println(Integer.parseInt(d.toString()));
} @Test
public void test2_1(){
// double 类型可以直接转为int类型
double dd = 1.1;
int ddd = (int)dd;
System.out.println(ddd);
} @Test
public void test2_2(){
// 可以通过强转进行转换,Double是包装类,不能直接进行强转,可以拆箱之后再次强转。
int aa = (int)(Double.parseDouble(d.toString()));
System.out.println(aa);
} @Test
public void test3(){
// 这种方式最为简单
System.out.println(d.intValue());
} @Test
public void test4(){
DecimalFormat format1 = new DecimalFormat("#");
String s = format1.format(d);
System.out.println(s);
} @Test
public void test5(){
DecimalFormat format1 = new DecimalFormat("#.#");
String s = format1.format(1.35);
System.out.println(s);
} @Test
public void test6(){
DecimalFormat format1 = new DecimalFormat("0.000");
String s = format1.format(1.35);
System.out.println(s);
}

DecimalFormat 要四舍五入需要加上 setRoundingMode(RoundingMode.HALF_UP); 网上是这么说的,但是自己测试默认就会四舍五入

特殊字符说明
“0” 指定位置不存在数字则显示为0 123.123 ->0000.0000 ->0123.1230
“#” 指定位置不存在数字则不显示 123.123 -> ####.#### ->123.123
“.” 小数点
“%” 会将结果数字乘以100 后面再加上% 123.123 ->#.00->1.3212%

嗯,就这么个坑了。

double转换为int以及浮点型相加损失精度问题的更多相关文章

  1. 从‘void*’到‘int’的转换损失精度

    在CentOS6.2 64位下编译一下代码,不通过,提示 ./11_2.cpp: In function ‘int main(int, char**)’:./11_2.cpp:28: 错误:从‘voi ...

  2. C++中将string类型转换为int, float, double类型 主要通过以下几种方式:

      C++中将string类型转换为int, float, double类型 主要通过以下几种方式: # 方法一: 使用stringstream stringstream在int或float类型转换为 ...

  3. double类型转换为int类型四舍五入工具类

    package com.qiyuan.util; import java.math.BigDecimal; import java.text.DecimalFormat; public class G ...

  4. pandas把'<m8[ns]'类型转换为int类型进行运算

    工作中经常碰到两列数据为date类型,当这两列数据相减或者相加时,得到天数,当运用这个值进行运算会报错:ufunc true_divide cannot use operands with types ...

  5. java把含小数点的数字字符串转换为int类型

    String num ="1.00"; int abc =Double.valueOf(num).intValue();//转换为Int类型

  6. string型的“600.000”如何转换为int型

    string型的“600.000”怎么转换为int型?为什么我用int.parse不能转换? ------解决方案--------------------int.Parse("600.000 ...

  7. Linux C 知识 char型数字转换为int型 int型 转换为Char

    前言 在九度oj做acm的时候,经常会遇到了char类型和int类型相互转化的问题,这里进行一下总结.今后,可能会多次更新博客,因为半年做了很多总结,但是都是保存在word文档上了,现在开始慢慢向CS ...

  8. int([x[, base]]) : 将一个字符转换为int类型,base表示进制

    int([x[, base]]) : 将一个字符转换为int类型,base表示进制 >>> int(-12) -12 >>> int(-12.00) -12 > ...

  9. android十六进制颜色代码转换为int类型数值

    android开发中将十六进制颜色代码转换为int类型数值方法:Color.parseColor("#00CCFF")返回int数值;

随机推荐

  1. [kuangbin]树链剖分A - Aragorn's Story

    比较水的题了,比模板题还要简单一点 理解了这个结构,自己打出来的,但是小错误还是很多,越来越熟练吧希望 错误函数updata,updata_lca,query||错误地方区间往下递归的时候是left ...

  2. POJ1644状态转移的思想——排列组合

    m个物品放n个盒子,盒子物品都相同,问你放的方法总数是多少 看着像个排列组合,算着算着就发现我排列组合都忘得差不多啦,哎,什么时候能打败遗忘呢 然后想用dp做,但是转移的方面没有想好 看了看题解感觉这 ...

  3. Anroid 手机助手 详细解析 概述(二)

    这篇主要说一下手机插入之后的一些动作. 1)  捕获窗口消息 插入拔出一个USB设备windows 会给所有的窗口发送特定的消息,只要我们捕获这些消息就可以处理设备插入和拔出.需要注意的是插入或者拔出 ...

  4. iOS4.0及以上系统,关闭程序,applicationWillTerminate为调用问题解决

    iOS4.0以后系统支持多任务类型,程序按下home键后,程序进入后台运行,如果内存不足被系统关闭或者手动关闭,都不会调用applicationWillTerminate回调函数. 解决方法:可以在程 ...

  5. jacoco初探

    # 背景 集团的代码覆盖率平台因为网络问题无法使用,只能自己研究下. 覆盖率是衡量自动化用例效果产品的一个指标,但只是一个辅助指标,覆盖率高并不意味着质量好,但覆盖率低却能说明一些问题, # 对比 覆 ...

  6. Git之初识

    我的Github地址:https://github.com/shinianzongjishinianxin 初见总是美好的,可是我第一次看到github有点纠结,因为看不懂,然而最终半蒙半猜还是注册完 ...

  7. 动态执行 VB.NET 和 C# 代码

    有时候我们需要尝试动态地与一些代码进行交互,而不是只能执行程序内已编死的代码,那该怎么办呢?我首先推荐各种脚本语言,如Javascript.Lua.Python等等,这些脚本语言有很多优秀的第三方类库 ...

  8. [学习笔记]后缀自动机SAM

    好抽象啊,早上看了两个多小时才看懂,\(\%\%\%Fading\) 早就懂了 讲解就算了吧--可以去看看其他人的博客 1.[模板]后缀自动机 \(siz\) 为该串出现的次数,\(l\) 为子串长度 ...

  9. 版本控制工具git

    公司要求用git,感觉不如svn好使,还是命令行的,暂时记录一下. 服务器是在linux上可以直接安装.我是虚拟机centos6.9版本.yum install -y git 查看版本号是git -- ...

  10. 使用Nginx转发TCP/UDP数据

    编译安装Nginx 从1.9.0开始,nginx就支持对TCP的转发,而到了1.9.13时,UDP转发也支持了.提供此功能的模块为ngx_stream_core.不过Nginx默认没有开启此模块,所以 ...