Java学习笔记:关于Java double类型相加问题

目录
  • Java double类型相加问题
    • 一、这个时候就要采用BigDecimal函数进行运算
    • 二、double 三种加法比较
  • Java Double类详解
    • Double 类的构造方法
    • Double 类的常用方法
    • Double 类的常用常量

Java double类型相加问题

多个double类型的数直接相加的时候,可能存在精度误差.( 由于计算机算法以及硬件环境决定只能识别 0 1。计算机默认的计算结果在都在一个指定精度范围之内,想往深的了解,可以学习数值分析等)

在金融方面是绝对不允许的,好在java开发者有这个先见之明。

java.math.*里面提供了BigDecimal类(提供高精度计算的方法)

一、这个时候就要采用BigDecimal函数进行运算

第一步、建立String类型的数据

第二步、创建BigDecimal对象BigDecimal(Double.toString(double))

以下两种不推荐:

BigDecimal(double)或者BigDecimal(Double.valueOf(double)))

建议: 涉及到精度问题的时候,整个计算过程都是用String类型或者BigDecimal类对象。最后结果根据需求 在转过来。

另外该文章提供了一个计算辅助类Java Double相加出现的怪事
急需的话,直接学习、创建该工具类,就可以完成项目了。以下是 加法算法的几个实现的方法。

new BigDecimal(Double.toString(double)).add(new BigDecimal(Double.toString(double));
    /**
     * @param b1
     *            BigDecimal
     * @param v2
     *            double
     * @return BigDecimal
     * */
    public BigDecimal add(BigDecimal b1, double v2) {
        // BigDecimal b1=new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.add(b2);
    }
    /**
     * @param b1
     *           double
     * @param v2
     *            double
     * @return BigDecimal
     * */
    public BigDecimal add(double v1, double v2) {
         BigDecimal b1=new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.add(b2);
    }
    /**
     * @param b1
     *           double
     * @param v2
     *            double
     * @return double
     * */
    public double add(double v1, double v2) {
         BigDecimal b1=new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.add(b2).doubleValue();
    }

二、double 三种加法比较

+,strictfp,BigDecimel

Strictfp —— Java 关键字。

可应用于类、接口或方法。

使用 strictfp 关键字声明一个方法时,该方法中所有的float和double表达式都严格遵守FP-strict的限制,符合IEEE-754规范。

严格约束意味着所有表达式的结果都必须是 IEEE 754 算法对操作数预期的结果,以单精度和双精度格式表示。

public class MathDemo {

    /**
     * @param args
     */
    public static void main(String[] args) {
        System.err.println("普通 "+ addNormal(12353.21,21334.24,154435.03));
        System.err.println("strictfp "+addDouble(12353.21,21334.24,154435.03));
        System.err.println("BigDEcimel: "+add(12353.21,21334.24,154435.03));

    }

    public static double addNormal(double... v1) {
        double res = 0;
        for (int i = 0; i < v1.length; i++) {
            res += v1[i];
        }
        return res;
    }

    public static strictfp double addDouble(double... v) {
        double res = 0;
        for (int i = 0; i < v.length; i++) {
            res += v[i];
        }
        return res;
    }

    /**
     * @param b1
     *            double
     * @param v2
     *            double
     * @return double
     */
    public static double add(double... v) {
        BigDecimal b  = new BigDecimal(Double.toString(v[0]));
        for (int i = 1; i < v.length; i++) {
            BigDecimal b2 = new BigDecimal(Double.toString(v[i]));
            b=b.add(b2);
        }
        return b.doubleValue();
    }
}

输入
12353.21,21334.24,154435.03三个类型的数据时候
结果:
普通 188122.47999999998
strictfp 188122.47999999998
BigDEcimel: 188122.48

输入
3.21, 4.24,5.03
结果
普通 12.48
strictfp 12.48
BigDEcimel: 12.48

输入:
12353.21,21334.24
结果:
普通 33687.45
strictfp 33687.45
BigDEcimel: 33687.45

结论是:

BigDecimal的算法精度比较好。 其余两种方法 都存在缺点。至于strictfp 这个关键字 是去平台化影响。比如32为机器和64位机器结果都一样。 对于精度计算结果影响不大。

附录:.

//使用double类型创建BigDecimal
  public BigDecimal(double val) {
        if (Double.isInfinite(val) || Double.isNaN(val))
            throw new NumberFormatException("Infinite or NaN");

        // Translate the double into sign, exponent and significand, according
        // to the formulae in JLS, Section 20.10.22.
        long valBits = Double.doubleToLongBits(val);
        int sign = ((valBits >> 63)==0 ? 1 : -1);
        int exponent = (int) ((valBits >> 52) & 0x7ffL);
        long significand = (exponent==0 ? (valBits & ((1L<<52) - 1)) << 1
                            : (valBits & ((1L<<52) - 1)) | (1L<<52));
        exponent -= 1075;
        // At this point, val == sign * significand * 2**exponent.

        /*
         * Special case zero to supress nonterminating normalization
         * and bogus scale calculation.
         */
        if (significand == 0) {
            intVal = BigInteger.ZERO;
            intCompact = 0;
            precision = 1;
            return;
        }

        // Normalize
        while((significand & 1) == 0) {    //  i.e., significand is even
            significand >>= 1;
            exponent++;
        }

        // Calculate intVal and scale
        long s = sign * significand;
        BigInteger b;
        if (exponent < 0) {
            b = BigInteger.valueOf(5).pow(-exponent).multiply(s);
            scale = -exponent;
        } else if (exponent > 0) {
            b = BigInteger.valueOf(2).pow(exponent).multiply(s);
        } else {
            b = BigInteger.valueOf(s);
        }
        intCompact = compactValFor(b);
        intVal = (intCompact != INFLATED) ? null : b;
    }

Java Double类详解

Double 类的构造方法

Double 类中的构造方法有如下两个。

  • Double(double value):构造一个新分配的 Double 对象,它表示转换为 double 类型的参数。
  • Double(String s):构造一个新分配的 Double 对象,它表示 String 参数所指示的 double 值。

分别使用以上两个构造方法获取 Double 对象:

Double double1 = new Double(5.556);    // 以 double 类型的变量作为参数创建 Double 对象
Double double2 = new Double("5.486");       // 以 String 类型的变量作为参数创建 Double 对象

Double 类的常用方法

如何将字符串 56.7809 转换为 double 类型的数值,或者将 double 类型的数值 56.7809 转换为对应的字符串呢?

String str = "56.7809";
double num = Double.parseDouble(str);    // 将字符串转换为 double 类型的数值
double d = 56.7809;
String s = Double.toString(d);    // 将double类型的数值转换为字符串

在将字符串转换为 double 类型的数值的过程中,如果字符串中包含非数值类型的字符,则程序执行将出现异常。

Double 类的常用常量

在 Double 类中包含了很多常量,其中较为常用的常量如下。

  • MAX_VALUE:值为 1.8E308 的常量,它表示 double 类型的最大正有限值的常量。
  • MIN_VALUE:值为 4.9E-324 的常量,它表示 double 类型数据能够保持的最小正非零值的常量。
  • NaN:保存 double 类型的非数字值的常量。
  • NEGATIVE_INFINITY:保持 double 类型的负无穷大的常量。
  • POSITIVE_INFINITY:保持 double 类型的正无穷大的常量。
  • SIZE:用秦以二进制补码形式表示 double 值的比特位数。
  • TYPE:表示基本类型 double 的 Class 实例。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • 完美解决java double数相加和相减的方案

    我就废话不多说了,大家还是直接看代码吧~ /** * double的计算不精确,会有类似0.0000000000000002的误差,正确的方法是使用BigDecimal或者用整型 * 整型地方法适合于货币精度已知的情况,比如12.11+1.10转成1211+110计算,最后再/100即可 * 以下是摘抄的BigDecimal方法: */ public class DoubleUtils implements Serializable { private static final long ser

  • java double类型相加精度问题的解决

    我就废话不多说了,大家还是直接看代码吧~ package com.hxyl.action; import java.text.DecimalFormat; public class Test { public static void main(String[] args) { // DecimalFormat 类主要靠 # 和 0 两种占位符号来指定数字长度.0 表示如果位数不足则以 0 填充,# 会把最后面的零默认省略. DecimalFormat df = new DecimalFormat

  • java中double类型运算结果异常的解决方法

    问题: 对两个double类型的值进行运算,有时会出现结果值异常的问题.比如: System.out.println(19.99+20); System.out.println(1.0-0.66); System.out.println(0.033*100); System.out.println(12.3/100); 输出: 39.989999999999995 0.33999999999999997 3.3000000000000003 0.12300000000000001 解决方法: J

  • Java用BigDecimal解决double类型相减时可能存在的误差

    double类型的两个数相减可能存在误差,比如System.out.println(2099 - 1999.9);的结果为99.09999999999991 可以用BigDecimal解决: public class TestDouble { //两个Double数相减 public static Double sub(Double d1, Double d2) { if (d1 == null || d2 == null) { return null; } BigDecimal b1 = ne

  • Java学习笔记:关于Java double类型相加问题

    目录 Java double类型相加问题 一.这个时候就要采用BigDecimal函数进行运算 二.double 三种加法比较 Java Double类详解 Double 类的构造方法 Double 类的常用方法 Double 类的常用常量 Java double类型相加问题 多个double类型的数直接相加的时候,可能存在精度误差.( 由于计算机算法以及硬件环境决定只能识别 0 1.计算机默认的计算结果在都在一个指定精度范围之内,想往深的了解,可以学习数值分析等) 在金融方面是绝对不允许的,好

  • java学习笔记之DBUtils工具包详解

    DBUtils工具包 一.介绍 DBUtils是Apache组织开源的数据库工具类. 二.使用步骤 ①.创建QueryRunner对象 ②.调用update()方法或者query()方法执行sql语句 三.构造方法及静态方法 QueryRunner类 1.构造方法 ①.无参构造 QueryRunner qr =new QueryRunner(); 使用无参构造的时候,调用update方法和query方法时就需要使用带Connection 类型参数的重载形式 ②.有参构造 QueryRunner

  • Java学习笔记:基本输入、输出数据操作实例分析

    本文实例讲述了Java学习笔记:基本输入.输出数据操作.分享给大家供大家参考,具体如下: 相关内容: 输出数据: print println printf 输入数据: Scanner 首发时间:2018-03-16 16:30 输出数据: JAVA中在屏幕中打印数据可以使用: System.out.print(x):x可以是一个变量.表达式.字符串. System.out.println(x):x可以是一个变量.表达式.字符串.与print不同的是打印完后会换行 System.out.print

  • java学习笔记_关于字符串概述

    一.String类 String类代表字符串,是由字符构成的一个序列.创建String对象的方法很简单,有以下几种: 1)用new来创建: String s1 = new String("my name is tongye"); 2) 不用new直接创建: String s2 = "my name is tongye"; 3) 可以用字符数组来创建一个字符串: char[] c = {'t','o','n','g','y','e'}; String s3 = new

  • Java用BigDecimal类解决Double类型精度丢失的问题

    本篇要点 简单描述浮点数十进制转二进制精度丢失的原因. 介绍几种创建BigDecimal方式的区别. 整理了高精度计算的工具类. 学习了阿里巴巴Java开发手册关于BigDecimal比较相等的规定. 经典问题:浮点数精度丢失 精度丢失的问题是在其他计算机语言中也都会出现,float和double类型的数据在执行二进制浮点运算的时候,并没有提供完全精确的结果.产生误差不在于数的大小,而是因为数的精度. 关于浮点数存储精度丢失的问题,话题过于庞大,感兴趣的同学可以自行搜索一下:[解惑]剖析floa

  • Java学习笔记之Maven篇

    一.maven能做什么? [本质]:将原材料(各种Java本身的类,不包括jar包)生产成为可运行的工程项目. Maven - 自动化构建工具,英文单词是专家内行的意思 1.方便管理jar包,jar包冲突? 2.打包web项目(节省jar包空间) 1.1 两大应用 [依赖管理]maven的jar包放在jar包仓库,maven只存储jar包的坐标.(代码重用思想) [一键构建]编译.测试.运行.打包.安装.部署 操作一体化 [POM:Project Object Model 工程对象模型 [pom

  • JAVA学习笔记:注释、变量的声明和定义操作实例分析

    本文实例讲述了JAVA学习笔记:注释.变量的声明和定义操作.分享给大家供大家参考,具体如下: 本文内容: 注释 变量的声明和定义 成员变量和局部变量 首发时间:2018-03-16 15:59 注释: 单行注释:// 多行注释:/* - */ 变量: 变量是内存中的一个存储区域,变量的定义就是给每一个变量名定义一个内存区域 JAVA中定义变量的格式为: 数据类型 变量名=初始化值,比如 变量可以先声明再定义,也可以声明并定义. 同类的变量可以一起声明,一起定义. 变量的使用要注意: 1.变量的作

  • Java学习笔记之面向对象编程精解

    目录 包 继承 super 关键字 final protected关键字 组合 多态 抽象类 接口 面向对象编程(包.继承.组合.多态 .抽象类.接口) 包 包其实就是类的集合,其本质上其实就是一个文件夹,里面存放的. java 文件里面有我们写的代码,并且包的存在还可以有效解决在实际开发过程中程序员. java文件命名重叠问题,其实就是,一个包里面是能有两个名字相同的.java文件,但是如果是不同的包下就允许这样的情况存在. 我们创建一个包只需要在 src 目录底下去创建就行了,公司里面给报的

  • JavaScript学习笔记之检测客户端类型是(引擎、浏览器、平台、操作系统、移动设备)

    //取得用户代理字符串 并全部小写. var ua = navigator.userAgent.toLowerCase(); document.write(ua); 在上篇文章给大家介绍了基于javascript代码检测访问网页的浏览器呈现引擎.平台.Windows操作系统.移动设备和游戏系统 ,感兴趣的朋友可以点击全文了解详情. 1.识别呈现引擎 引擎主要包含四种:IE.Gecko.WebKit.Opera 2.识别浏览器 主流浏览器包含四种:IE.Chrome.Firefox.Opera 3

随机推荐