java金融通貨処理
5107 ワード
回転:http://imtinx.iteye.com/blog/832325
「あなたが知らないかもしれないJava基礎知識(一)」では、浮動小数点演算を使うには慎重で、徹底した表現が足りないと言いましたが、floatとdoubleのタイプは主に科学と工事のために設計されています.彼らはバイナリ浮動小数点演算を実行していますが、バイナリの限界のために正確な結果が得られない場合があります.
例えば、System.out.println(2.0-1.1)は0.9ではなく0.89999999を出力します.もちろん科学計算では関係ないです.四捨五入で問題を簡単に解決できますが、丸め誤差が生じることが禁止されている演算には適用されません.
バイナリでは正確に10の負の乗平均値を表してはいけません.例えば、0.1というように、10進数の中で1/3を正確に表してはいけません.したがって、金融通貨のように計算する問題になればなるほど、floatとdoubleを捨ててBigDecimal類を変更しなければなりません.
「Effective Java」という本の中でもこの原則を言及しています.floatとdoubleは科学的な計算や工程計算をするしかないです.商業計算ではjava.math.Big Decimalを使います.またStringでBigDecimalを作るには無理です.『Effective Java』の本の中の例はStringでBigDecimalを作るのに十分ですが、本ではそれを強調していません.これは小さなミスかもしれません.
BigDecimalで上記の2.0-1.1問題を解決するコードは以下の通りです.
Javaコード コレクションコード
「あなたが知らないかもしれないJava基礎知識(一)」では、浮動小数点演算を使うには慎重で、徹底した表現が足りないと言いましたが、floatとdoubleのタイプは主に科学と工事のために設計されています.彼らはバイナリ浮動小数点演算を実行していますが、バイナリの限界のために正確な結果が得られない場合があります.
例えば、System.out.println(2.0-1.1)は0.9ではなく0.89999999を出力します.もちろん科学計算では関係ないです.四捨五入で問題を簡単に解決できますが、丸め誤差が生じることが禁止されている演算には適用されません.
バイナリでは正確に10の負の乗平均値を表してはいけません.例えば、0.1というように、10進数の中で1/3を正確に表してはいけません.したがって、金融通貨のように計算する問題になればなるほど、floatとdoubleを捨ててBigDecimal類を変更しなければなりません.
「Effective Java」という本の中でもこの原則を言及しています.floatとdoubleは科学的な計算や工程計算をするしかないです.商業計算ではjava.math.Big Decimalを使います.またStringでBigDecimalを作るには無理です.『Effective Java』の本の中の例はStringでBigDecimalを作るのに十分ですが、本ではそれを強調していません.これは小さなミスかもしれません.
BigDecimalで上記の2.0-1.1問題を解決するコードは以下の通りです.
Javaコード コレクションコード
import java.math.*;
class BigDecimalTest
{
public static void main(String[] args)
{
// BigDecimal
BigDecimal a =new BigDecimal("2.0");
BigDecimal b = new BigDecimal("1.1");
System.out.println(a.subtract(b));
}
}
:0.9
もしStringを使わずにBigDecimalを構築するなら、問題は元の通りになります. Javaコード コレクションコード import java.math.*;
class TestB
{
public static void main(String[] args)
{
// double BigDecimal,
BigDecimal a = new BigDecimal(2.0);
BigDecimal b = new BigDecimal(1.1);
System.out.println(a.subtract(b));
}
}
0.899999999999999911182158029987476766109466552734375
もちろんBigDecimalも丸め方法を提供しています.以下はオンラインで淘汰された種類です.これらの問題を完璧に解決しました. Javaコード コレクションコードpackage com.morningstar.bigdecimal;
import java.math.BigDecimal;
public class Arithmetic4Double {
//
private static final int DEF_DIV_SCALE = 10;
// ,
private Arithmetic4Double() {}
/**
*
* @param v1 1
* @param v2 2
* @return v1+v2
*/
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 v1-v2
*/
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 v1×v2
*/
public static double multi(double v1,double v2) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.multiply(b2).doubleValue();
}
/**
*
* , DEF_DIV_SCALE ( 10 ), 。
* @param v1
* @param v2
* @return v1/v2
*/
public static double div(double v1,double v2) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.divide(b2,DEF_DIV_SCALE,BigDecimal.ROUND_HALF_UP).doubleValue();
}
/**
*
* , scale , 。
* @param v1
* @param v2
* @param scale
* @return v1/v2
*/
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();
}
}
一言をまとめます.正確な演算はString構造のBig Decimalを使います.floatとdoubleを使わないでください.