深入学习java源码之Double.parseDouble()与Double.valueOf()

深入学习java源码之Double.parseDouble()与Double.valueOf() 

Double类是原始类型double的包装类,它包含若干有效处理double值的方法,如将其转换为字符串表示形式,反之亦然。Double类的对象可以包含一个double值。

public class Double_test
{
 
    public static void main(String[] args)
    {
        
        double b = 55.05;
        String bb = "45";
 
        // Construct two Double objects
        Double x = new Double(b);
        Double y = new Double(bb);
 
        // toString()
        System.out.println("toString(b) = " + Double.toString(b));
 
        // valueOf()
        // return Double object
        Double z = Double.valueOf(b);
        System.out.println("valueOf(b) = " + z);
        z = Double.valueOf(bb);
        System.out.println("ValueOf(bb) = " + z);
 
        // parseDouble()
        // return primitive double value
        double zz = Double.parseDouble(bb);
        System.out.println("parseDouble(bb) = " + zz);
 
        System.out.println("bytevalue(x) = " + x.byteValue());
        System.out.println("shortvalue(x) = " + x.shortValue());
        System.out.println("intvalue(x) = " + x.intValue());
        System.out.println("longvalue(x) = " + x.longValue());
        System.out.println("doublevalue(x) = " + x.doubleValue());
        System.out.println("floatvalue(x) = " + x.floatValue());
 
        int hash = x.hashCode();
        System.out.println("hashcode(x) = " + hash);
 
        boolean eq = x.equals(y);
        System.out.println("x.equals(y) = " + eq);
 
        int e = Double.compare(x, y);
        System.out.println("compare(x,y) = " + e);
 
        int f = x.compareTo(y);
        System.out.println("x.compareTo(y) = " + f);
 
        Double d = Double.valueOf("1010.54789654123654");
        System.out.println("isNaN(d) = " + d.isNaN());
 
        System.out.println("Double.isNaN(45.12452) = " + Double.isNaN(45.12452));
 
        // Double.POSITIVE_INFINITY stores
        // the positive infinite value
        d = Double.valueOf(Double.POSITIVE_INFINITY + 1);
        System.out.println("Double.isInfinite(d) = " + 
                                    Double.isInfinite(d.doubleValue()));
 
        double dd = 10245.21452;
        System.out.println("Double.toString(dd) = " + Double.toHexString(dd));
 
        long double_to_long = Double.doubleToLongBits(dd);
        System.out.println("Double.doubleToLongBits(dd) = " + double_to_long);
 
        double long_to_double = Double.longBitsToDouble(double_to_long);
        System.out.println("Double.LongBitsToDouble(double_to_long) = " + 
                                    long_to_double);
    }
 
}

输出:

toString(b) = 55.05
valueOf(b) = 55.05
ValueOf(bb) = 45.0
parseDouble(bb) = 45.0
bytevalue(x) = 55
shortvalue(x) = 55
intvalue(x) = 55
longvalue(x) = 55
doublevalue(x) = 55.05
floatvalue(x) = 55.05
hashcode(x) = 640540672
x.equals(y) = false
compare(x,y) = 1
x.compareTo(y) = 1
isNaN(d) = false
Double.isNaN(45.12452) = false
Double.isInfinite(d) = true
Double.toString(dd) = 0x1.4029b7564302bp13
Double.doubleToLongBits(dd) = 4666857980575363115
Double.LongBitsToDouble(double_to_long) = 10245.21452

 

Double类型的计算

如果我们编译运行下面这个程序会看到什么?

public class Test{
    public static void main(String args[]){
        System.out.println(0.05+0.01);
        System.out.println(1.0-0.42);
        System.out.println(4.015*100);
        System.out.println(123.3/100);
    }
};

你没有看错!结果确实是

0.060000000000000005
0.5800000000000001
401.49999999999994
1.2329999999999999

Java中的简单浮点数类型float和double不能够进行运算。不光是Java,在其它很多编程语言中也有这样的问题。在大多数情况下,计算的结果是准确的,但是多试几次(可以做一个循环)就可以试出类似上面的错误。现在终于理解为什么要有BCD码了。
这个问题相当严重,如果你有9.999999999999元,你的计算机是不会认为你可以购买10元的商品的。
在有的编程语言中提供了专门的货币类型来处理这种情况,但是Java没有。现在让我们看看如何解决这个问题。
 
四舍五入
我们的第一个反应是做四舍五入。Math类中的round方法不能设置保留几位小数,我们只能象这样(保留两位):

public double round(double value){
    return Math.round(value*100)/100.0;
}

非常不幸,上面的代码并不能正常工作,给这个方法传入4.015它将返回4.01而不是4.02,如我们在上面看到的
4.015*100=401.49999999999994
因此如果我们要做到精确的四舍五入,不能利用简单类型做任何运算
java.text.DecimalFormat也不能解决这个问题:

System.out.println(new java.text.DecimalFormat("0.00").format(4.025));

输出是4.02

精确计算

float和double只能用来做科学计算或者是工程计算,在商业计算中我们要用 java.math.BigDecimal

我们如果需要精确计算,非要用String来够造BigDecimal不可!

divide方法中推荐使用枚举RoundingMode.HALF_UP

 import java.io.Serializable;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
 /**
  * double的计算不精确,会有类似0.0000000000000002的误差,正确的方法是使用BigDecimal或者用整型
  * 整型地方法适合于货币精度已知的情况,比如12.11+1.10转成1211+110计算,最后再/100即可
  * 以下是摘抄的BigDecimal方法:
  */
 public class DoubleUtil implements Serializable {
     private static final long serialVersionUID = -3345205828566485102L;
     // 默认除法运算精度
     private static final Integer DEF_DIV_SCALE = 2;
 
     /**
      * 提供精确的加法运算。
      *
      * @param value1 被加数
      * @param value2 加数
      * @return 两个参数的和
      */
     public static Double add(Double value1, Double value2) {
         BigDecimal b1 = new BigDecimal(Double.toString(value1));
         BigDecimal b2 = new BigDecimal(Double.toString(value2));
         return b1.add(b2).doubleValue();
     }
 
     /**
      * 提供精确的减法运算。
      *
      * @param value1 被减数
      * @param value2 减数
      * @return 两个参数的差
      */
     public static double sub(Double value1, Double value2) {
         BigDecimal b1 = new BigDecimal(Double.toString(value1));
         BigDecimal b2 = new BigDecimal(Double.toString(value2));
         return b1.subtract(b2).doubleValue();
     }
 
     /**
      * 提供精确的乘法运算。
      *
      * @param value1 被乘数
      * @param value2 乘数
      * @return 两个参数的积
      */
     public static Double mul(Double value1, Double value2) {
         BigDecimal b1 = new BigDecimal(Double.toString(value1));
         BigDecimal b2 = new BigDecimal(Double.toString(value2));
         return b1.multiply(b2).doubleValue();
     }
 
     /**
      * 提供(相对)精确的除法运算,当发生除不尽的情况时, 精确到小数点以后10位,以后的数字四舍五入。
      *
      * @param dividend 被除数
      * @param divisor  除数
      * @return 两个参数的商
      */
     public static Double divide(Double dividend, Double divisor) {
         return divide(dividend, divisor, DEF_DIV_SCALE);
     }
 
     /**
      * 提供(相对)精确的除法运算。 当发生除不尽的情况时,由scale参数指定精度,以后的数字四舍五入。
      *
      * @param dividend 被除数
      * @param divisor  除数
      * @param scale    表示表示需要精确到小数点以后几位。
      * @return 两个参数的商
      */
     public static Double divide(Double dividend, Double divisor, Integer scale) {
         if (scale < 0) {
             throw new IllegalArgumentException("The scale must be a positive integer or zero");
         }
         BigDecimal b1 = new BigDecimal(Double.toString(dividend));
         BigDecimal b2 = new BigDecimal(Double.toString(divisor));
         return b1.divide(b2, scale,RoundingMode.HALF_UP).doubleValue();
     }
 
     /**
      * 提供指定数值的(精确)小数位四舍五入处理。
      *
      * @param value 需要四舍五入的数字
      * @param scale 小数点后保留几位
      * @return 四舍五入后的结果
      */
     public static double round(double value,int scale){
         if(scale<0){
             throw new IllegalArgumentException("The scale must be a positive integer or zero");
         }
         BigDecimal b = new BigDecimal(Double.toString(value));
         BigDecimal one = new BigDecimal("1");
         return b.divide(one,scale, RoundingMode.HALF_UP).doubleValue();
     }
 }

 

 

Modifier and TypeMethod and Description
bytebyteValue()

返回此值 Doublebyte的基本收缩转换后。

static intcompare(double d1, double d2)

比较两个指定的 double值。

intcompareTo(Double anotherDouble)

数字比较两个 Double对象。

static longdoubleToLongBits(double value)

根据IEEE 754浮点“双格式”位布局返回指定浮点值的表示。

static longdoubleToRawLongBits(double value)

根据IEEE 754浮点“双格式”位布局返回指定浮点值的表示,保留非数字(NaN)值。

doubledoubleValue()

返回此 Double对象的 double值。

booleanequals(Object obj)

将此对象与指定对象进行比较。

floatfloatValue()

返回此值 Doublefloat的基本收缩转换后。

inthashCode()

返回此 Double对象的哈希码。

static inthashCode(double value)

返回一个double值的哈希码; 兼容Double.hashCode()

intintValue()

int后,返回 Double作为int的值。

static booleanisFinite(double d)

如果参数是有限浮点值,则返回true ; 返回false (对于NaN和无穷大参数)。

booleanisInfinite()

返回 true如果这 Double值是无限大, false其他。

static booleanisInfinite(double v)

返回 true如果指定的数量是无限大, false其他。

booleanisNaN()

如果 DoubleDouble数字(NaN),则返回 truefalse false。

static booleanisNaN(double v)

如果指定的数字是非数字(NaN)值,则返回 truefalse false。

static doublelongBitsToDouble(long bits)

返回与给 double表示相对应的 double值。

longlongValue()

返回此值 Doublelong的基本收缩转换后。

static doublemax(double a, double b)

返回两个 double值中的较大值,就像调用 Math.max一样

static doublemin(double a, double b)

返回两个 double的较小值,就像调用 Math.min一样

static doubleparseDouble(String s)

返回一个新 double初始化为指定的代表的值 String ,如通过执行 valueOf类的方法 Double

shortshortValue()

返回此值 Doubleshort的基本收缩转换后。

static doublesum(double a, double b)

按照+运算符将两个 double值一起添加。

static StringtoHexString(double d)

返回 double参数的十六进制字符串 double形式。

StringtoString()

返回此 Double对象的字符串表示形式。

static StringtoString(double d)

返回 double参数的字符串 double形式。

static DoublevalueOf(double d)

返回一个 Double double值的 Double实例。

static DoublevalueOf(String s)

返回一个 Double对象,保存由参数字符串 sdouble值。

java源码

package java.lang;

import sun.misc.FloatingDecimal;
import sun.misc.FpUtils;
import sun.misc.DoubleConsts;

public final class Double extends Number implements Comparable<Double> {

    public static final double POSITIVE_INFINITY = 1.0 / 0.0;

    public static final double NEGATIVE_INFINITY = -1.0 / 0.0;

    public static final double NaN = 0.0d / 0.0;

    public static final double MAX_VALUE = 0x1.fffffffffffffP+1023; // 1.7976931348623157e+308

    public static final double MIN_NORMAL = 0x1.0p-1022; // 2.2250738585072014E-308

    public static final double MIN_VALUE = 0x0.0000000000001P-1022; // 4.9e-324

    public static final int MAX_EXPONENT = 1023;

    public static final int MIN_EXPONENT = -1022;

    public static final int SIZE = 64;

    public static final int BYTES = SIZE / Byte.SIZE;

    @SuppressWarnings("unchecked")
    public static final Class<Double>   TYPE = (Class<Double>) Class.getPrimitiveClass("double");

    public static String toString(double d) {
        return FloatingDecimal.toJavaFormatString(d);
    }

    public static String toHexString(double d) {
        /*
         * Modeled after the "a" conversion specifier in C99, section
         * 7.19.6.1; however, the output of this method is more
         * tightly specified.
         */
        if (!isFinite(d) )
            // For infinity and NaN, use the decimal output.
            return Double.toString(d);
        else {
            // Initialized to maximum size of output.
            StringBuilder answer = new StringBuilder(24);

            if (Math.copySign(1.0, d) == -1.0)    // value is negative,
                answer.append("-");                  // so append sign info

            answer.append("0x");

            d = Math.abs(d);

            if(d == 0.0) {
                answer.append("0.0p0");
            } else {
                boolean subnormal = (d < DoubleConsts.MIN_NORMAL);

                // Isolate significand bits and OR in a high-order bit
                // so that the string representation has a known
                // length.
                long signifBits = (Double.doubleToLongBits(d)
                                   & DoubleConsts.SIGNIF_BIT_MASK) |
                    0x1000000000000000L;

                // Subnormal values have a 0 implicit bit; normal
                // values have a 1 implicit bit.
                answer.append(subnormal ? "0." : "1.");

                // Isolate the low-order 13 digits of the hex
                // representation.  If all the digits are zero,
                // replace with a single 0; otherwise, remove all
                // trailing zeros.
                String signif = Long.toHexString(signifBits).substring(3,16);
                answer.append(signif.equals("0000000000000") ? // 13 zeros
                              "0":
                              signif.replaceFirst("0{1,12}$", ""));

                answer.append('p');
                // If the value is subnormal, use the E_min exponent
                // value for double; otherwise, extract and report d's
                // exponent (the representation of a subnormal uses
                // E_min -1).
                answer.append(subnormal ?
                              DoubleConsts.MIN_EXPONENT:
                              Math.getExponent(d));
            }
            return answer.toString();
        }
    }

    public static Double valueOf(String s) throws NumberFormatException {
        return new Double(parseDouble(s));
    }

    public static Double valueOf(double d) {
        return new Double(d);
    }
	
    public static double parseDouble(String s) throws NumberFormatException {
        return FloatingDecimal.parseDouble(s);
    }	
	
    public static boolean isNaN(double v) {
        return (v != v);
    }
	
    public static boolean isInfinite(double v) {
        return (v == POSITIVE_INFINITY) || (v == NEGATIVE_INFINITY);
    }	
	
    public static boolean isFinite(double d) {
        return Math.abs(d) <= DoubleConsts.MAX_VALUE;
    }	
	
    private final double value;	
	
    public Double(double value) {
        this.value = value;
    }	
	
    public Double(String s) throws NumberFormatException {
        value = parseDouble(s);
    }	
	
    public boolean isNaN() {
        return isNaN(value);
    }	
	
    public boolean isInfinite() {
        return isInfinite(value);
    }	
	
    public String toString() {
        return toString(value);
    }
	
    public byte byteValue() {
        return (byte)value;
    }	
	
    public short shortValue() {
        return (short)value;
    }	
	
    public int intValue() {
        return (int)value;
    }	
	
    public long longValue() {
        return (long)value;
    }	
	
    public float floatValue() {
        return (float)value;
    }	
	
    public double doubleValue() {
        return value;
    }	
	
    @Override
    public int hashCode() {
        return Double.hashCode(value);
    }	
	
    public static int hashCode(double value) {
        long bits = doubleToLongBits(value);
        return (int)(bits ^ (bits >>> 32));
    }	
	
    public boolean equals(Object obj) {
        return (obj instanceof Double)
               && (doubleToLongBits(((Double)obj).value) ==
                      doubleToLongBits(value));
    }	
	
    public static long doubleToLongBits(double value) {
        long result = doubleToRawLongBits(value);
        // Check for NaN based on values of bit fields, maximum
        // exponent and nonzero significand.
        if ( ((result & DoubleConsts.EXP_BIT_MASK) ==
              DoubleConsts.EXP_BIT_MASK) &&
             (result & DoubleConsts.SIGNIF_BIT_MASK) != 0L)
            result = 0x7ff8000000000000L;
        return result;
    }	
	
    public static native long doubleToRawLongBits(double value);	
	
    public static native double longBitsToDouble(long bits);	
	
    public int compareTo(Double anotherDouble) {
        return Double.compare(value, anotherDouble.value);
    }
	
    public static int compare(double d1, double d2) {
        if (d1 < d2)
            return -1;           // Neither val is NaN, thisVal is smaller
        if (d1 > d2)
            return 1;            // Neither val is NaN, thisVal is larger

        // Cannot use doubleToRawLongBits because of possibility of NaNs.
        long thisBits    = Double.doubleToLongBits(d1);
        long anotherBits = Double.doubleToLongBits(d2);

        return (thisBits == anotherBits ?  0 : // Values are equal
                (thisBits < anotherBits ? -1 : // (-0.0, 0.0) or (!NaN, NaN)
                 1));                          // (0.0, -0.0) or (NaN, !NaN)
    }	
	
    public static double sum(double a, double b) {
        return a + b;
    }	
	
    public static double max(double a, double b) {
        return Math.max(a, b);
    }	

    public static double min(double a, double b) {
        return Math.min(a, b);
    }
	
    private static final long serialVersionUID = -9172774392245257468L;
}	
package java.lang;
import java.util.*;

public interface Comparable<T> {
    public int compareTo(T o);
}
package java.lang;

public abstract class Number implements java.io.Serializable {

    public abstract int intValue();

    public abstract long longValue();

    public abstract float floatValue();

    public abstract double doubleValue();

    public byte byteValue() {
        return (byte)intValue();
    }

    public short shortValue() {
        return (short)intValue();
    }
	
    private static final long serialVersionUID = -8742448824652078965L;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wespten

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值