您的位置:首页 > 其它

高精度运算类(BigInteger,BigDecimal)

2008-09-13 11:07 429 查看
主类型 大小 最小值 最大值 封装器类型
boolean - - - Boolean
Char 16-bit Unicode 0 Unicode 216- 1 Character
byte 8-bit -128 +127 Byte
Short 16-bit -215 +215?1 Short
Int 32-bit -231 +231?1 Integer
Long 64-bit -263 +263?1 Long
Float 32-bit IEEE754 IEEE754 Float
double 64-bit IEEE754 IEEE754 Double
Void - - - Void

简单类型变量和包装类之间的相互转换 简单类型的变量转换为相应的包装类,可以利用包装类的构造函数。即:
Boolean(boolean value);
Character(char value);
Integer(int value);
Long(long value);
Float(float value);
Double(double value)

String类和其它数据类型的相互转换 对于上面的这些包装类,除了Character以外,都有可以直接使用字符串参数的构造函数,这也就使得我们将String类转换为这些数据类型变得相当之简单,即:
Boolean(String s);
Integer(String s);
Long(String s);
Float(String s);
Double(String s);

1.高精度数字
Java 提供了两个类专门用于进行高精度运算BigInteger 和 BigDecimal ,尽管它们可大致划分到与封装器相同的类别里,但两者都没有对应的主类型;这两个类都有自己的一系列方法,类似于我们针对主类型执行的操作,也就是说能用int 或float 做的事情,用BigInteger和BigDecimal 一样可以做,只是必须换用方法调用,而不是使用运算符。此外由于牵涉更多,所以运算速度会慢一点总之我们牺牲了速度,但换来了精度。

1.1高精度浮点数BigDecimal
一些非整数值(如几美元和几美分这样的小数)需要很精确。浮点数不是精确值,所以使用它们会导致舍入误差。因此,使用浮点数来试图表示象货币量这样的精确数量不是一个好的想法。使用浮点数来进行美元和美分计算会得到灾难性的后果。浮点数最好用来表示象测量值这类数值,这类值从一开始就不怎么精确。
从 JDK 1.3 起,Java 开发人员就有了另一种数值表示法来表示非整数:BigDecimal。BigDecimal 是标准的类,在编译器中不需要特殊支持,它可以表示任意精度的小数,并对它们进行计算。在内部,可以用任意精度任何范围的值和一个换算因子来表示 BigDecimal,换算因子表示左移小数点多少位,从而得到所期望范围内的值。因此,用 BigDecimal 表示的数的形式为 unscaledValue*10-scale。
  用于加、减、乘和除的方法给 BigDecimal 值提供了算术运算。由于 BigDecimal 对象是不可变的,这些方法中的每一个都会产生新的 BigDecimal 对象。因此,因为创建对象的开销,BigDecimal 不适合于大量的数学计算,但设计它的目的是用来精确地表示小数。如果您正在寻找一种能精确表示如货币量这样的数值,则 BigDecimal 可以很好地胜任该任务。
  如浮点类型一样,BigDecimal 也有一些令人奇怪的行为。尤其在使用 equals() 方法来检测数值之间是否相等时要小心。equals() 方法认为,两个表示同一个数但换算值不同(例如,100.00 和 100.000)的 BigDecimal 值是不相等的。然而,compareTo() 方法会认为这两个数是相等的,所以在从数值上比较两个 BigDecimal 值时,应该使用 compareTo() 而不是 equals()。
  另外还有一些情形,任意精度的小数运算仍不能表示精确结果。例如,1 除以 9 会产生无限循环的小数 .111111...。出于这个原因,在进行除法运算时,BigDecimal 可以让您显式地控制舍入。movePointLeft() 方法支持 10 的幂次方的精确除法。
  对于 BigDecimal,有几个可用的构造函数。其中一个构造函数以双精度浮点数作为输入,另一个以整数和换算因子作为输入,还有一个以小数的 String 表示作为输入。要小心使用 BigDecimal(double) 构造函数,因为如果不了解它,会在计算过程中产生舍入误差。请使用基于整数或 String 的构造函数。
如果使用 BigDecimal(double) 构造函数不恰当,在传递给 JDBC setBigDecimal() 方法时,会造成似乎很奇怪的 JDBC 驱动程序中的异常。例如,考虑以下 JDBC 代码,该代码希望将数字 0.01 存储到小数字段:
PreparedStatement ps =connection.prepareStatement("INSERT INTO Foo SET name=?, value=?");
ps.setString(1, "penny");
ps.setBigDecimal(2, new BigDecimal(0.01));
ps.executeUpdate();
在执行这段似乎无害的代码时会抛出一些令人迷惑不解的异常(这取决于具体的 JDBC 驱动程序),因为 0.01 的双精度近似值会导致大的换算值,这可能会使 JDBC 驱动程序或数据库感到迷惑。JDBC 驱动程序会产生异常,但可能不会说明代码实际上错在哪里,除非意识到二进制浮点数的局限性。相反,使用 BigDecimal("0.01") 或 BigDecimal(1, 2) 构造 BigDecimal 来避免这类问题,因为这两种方法都可以精确地表示小数。
import java.math.BigDecimal;
/** * *
* <p>Title: 开源,开放</p>
* * <p>Description: opeansource</p>
* * <p>Copyright: Copyright (c) 2004</p>
* * <p>Company: ?海棠</p>
* * @author HaiTang Ming
* * @version 1.0 */
public class BigDecimalUtil {
//默认除法运算精度,及即保留小数点多少位
private static final int DEF_DIV_SCALE = 2;
//这个类不能实例化
private BigDecimalUtil (){ }
/**
* * 提供精确的加法运算。
* * @param v1 被加数
* * @param v2 加数
* * @return 两个参数的和
* */
public static 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();
}
/**
* * 提供精确的减法运算。
* * @param v1 被减数
* * @param v2 减数
* * @return 两个参数的差
**/
public static double sub(double v1,double v2){
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return (b1.subtract(b2)).doubleValue();
}
/**
* * 提供精确的乘法运算。
* * @param v1 被乘数
* * @param v2 乘数
* * @return 两个参数的积
* */
public static double mul(double v1,double v2){
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return (b1.multiply(b2)).doubleValue();
}
/**
* * 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到
* * 小数点以后多少位,以后的数字四舍五入。
* * @param v1 被除数
* * @param v2 除数
* * @return 两个参数的商
* */
public static double div(double v1,double v2){
return div(v1,v2,DEF_DIV_SCALE);
}
/**
* * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指
* * 定精度,以后的数字四舍五入。
* * @param v1 被除数
* @param v2 除数
* * @param scale 表示表示需要精确到小数点以后几位。
* * @return 两个参数的商
* */
public static double div(double v1,double v2,int scale){
if(scale<0){
throw new IllegalArgumentException("The scale must be a positive integer or zero");
}
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return (b1.divide(b2,scale,BigDecimal.ROUND_HALF_UP)).doubleValue();
}
/**
* * 提供精确的小数位四舍五入处理。
* * @param v 需要四舍五入的数字
* * @param scale 小数点后保留几位
* * @return 四舍五入后的结果
* */
public static double round(double v,int scale){
if(scale<0){
throw new IllegalArgumentException("The scale must be a positive integer or zero");
}
BigDecimal b = new BigDecimal(Double.toString(v));
BigDecimal one = new BigDecimal("1");
return (b.divide(one,scale,BigDecimal.ROUND_HALF_UP)).doubleValue();
}
public static void main(String[] args){
System.out.println(add(234.44,534.90));

double a = 123.345678;
double d = round(a,2);
System.out.println("round("+a+",2)--->"+d);
}
}
1.2 高精度整数BigInteger
BigInteger支持任意精度的整数,也就是说我们可精确表示任意大小的整数值;同时在运算过程中不会丢失任何信息;
在BigInteger类中有所有的基本算术运算方法,如加、减、乘、除,以及可能会用到的位运算如或、异或、非、左移、右移等。下面是一些方法的例子:当然,如果要有更多的使用方法,可以查阅java api 。
public class BigIntegerTest {
public BigIntegerTest() { }
/**
* * 测试BigInteger
* */
public static void testBigInteger() {
BigInteger bi = new BigInteger("888");
//multiply :乘法
BigInteger result = bi.multiply(new BigInteger("2"));
System.out.println(result);
//divide : 除法
result = bi.divide(new BigInteger("2"));
System.out.println(result);
//add : 加法
result = bi.add(new BigInteger("232"));
System.out.println(result);
//subtract :减法
result = bi.subtract(new BigInteger("23122"));
System.out.println(result);
result = bi.shiftRight(2);
System.out.println(result);
}
public static void main(String[] args) {
testBigInteger();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: