Java バックエンドは加算、減算、乗算、除算、比率の計算を実装します。
API クラス BigDecimal は、有効数字 16 桁を超える数値に対して正確な演算を実行するために java.math パッケージで提供されています。
BigDecimal が作成するものはオブジェクトであるため、+、-、*、/ などの算術演算子を使用してそのオブジェクトに対して直接数学演算を実行することはできません。
まず、BigDecimal には 4 つの構築メソッドがあることを理解する必要があります。
//创建一个具有参数所指定整数值的对象
BigDecimal(int)
//创建一个具有参数所指定双精度值的对象
BigDecimal(double)
//创建一个具有参数所指定整数值的对象
BigDecimal(long)
//创建一个具有参数所指定以字符串表示的数值的对象
BigDecimal(String)
//这里对比了两种形式,第一种直接value写数字的值,第二种用string来表示
BigDecimal num1 = new BigDecimal(0.005);
BigDecimal num2 = new BigDecimal(1000000);
BigDecimal num3 = new BigDecimal(-1000000);
//尽量用字符串的形式初始化
BigDecimal num12 = new BigDecimal("0.005");
BigDecimal num22 = new BigDecimal("1000000");
BigDecimal num32 = new BigDecimal("-1000000");
1. 足し算、引き算、掛け算、割り算
//加法 add()
BigDecimal result1 = num1.add(num2);
BigDecimal result12 = num12.add(num22);
//减法 subtract()
BigDecimal result2 = num1.subtract(num2);
BigDecimal result22 = num12.subtract(num22);
//乘法 multiply()
BigDecimal result3 = num1.multiply(num2);
BigDecimal result32 = num12.multiply(num22);
//绝对值 abs()
BigDecimal result4 = num3.abs();
BigDecimal result42 = num32.abs();
//除法 divide()
//num1、num12 除数, 20 精确小数位, BigDecimal.ROUND_HALF_UP 舍入模式
BigDecimal result5 = num2.divide(num1,20,BigDecimal.ROUND_HALF_UP);
BigDecimal result52 = num22.divide(num12,20,BigDecimal.ROUND_HALF_UP);
//去除末尾多余的0:
new BigDecimal("100.000").stripTrailingZeros().toPlainString();
結果を確認するには、ここにすべての結果を出力します
。ここには違いがあるため、初期化には文字列を使用することをお勧めします
※注意:
1) System.out.println() の数値はデフォルトでは double 型であり、double 型の 10 進数の計算は不正確です。
2) BigDecimal クラス構築メソッドを使用して double 型を渡すと、計算結果も不正確になります。
すべての浮動小数点数を double 型の値として正確に表現できるわけではないため、一部の浮動小数点値は double 型の値として正確に表現できないため、最も近い double 型の値として表現されます。代わりに String を渡すコンストラクターを使用する必要があります。この点は、BigDecimal クラスのコンストラクター アノテーションで説明されています。
除算 Division() パラメータは次を使用します。
除算関数を使用して除算する場合、さまざまなパラメータ、正確な小数点以下の桁数、丸めモードを設定する必要があり、そうでないとエラーが発生します。
//即为(BigDecimal divisor 除数, int scale 精确小数位, int roundingMode 舍入模式)
Public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode)
しかし、BigDecimal.ROUND_XXXX_XXX という丸めモードにはさまざまな種類がありますが、具体的には何を意味するのでしょうか?
8 つの丸めモードについては次のように説明します。
1)ラウンドアップ
ゼロから四捨五入するための丸めモード。
ゼロ以外の部分を破棄する前に、常に数値をインクリメントします (ゼロ以外の破棄された部分の前の数値に常に 1 を加算します)。
この丸めモードでは、計算値のサイズが決して小さくならないことに注意してください。
2)ROUND_DOWN
ゼロに近い丸めモード。
一部が破棄されるまで数値を増分しないでください (破棄された部分の前の数値に 1 を加えないでください。つまり、切り捨てられます)。
この丸めモードでは、計算値のサイズは決して増加しないことに注意してください。
3)丸い天井
正の無限大に向かう丸めモード。
BigDecimal が正の場合、丸め動作は ROUND_UP と同じになります。
負の場合、丸め動作は ROUND_DOWN と同じになります。
この丸めモードでは計算値が決して減らないことに注意してください。
4)ラウンドフロア
負の無限大に近い丸めモード。
BigDecimal が正の場合、丸め動作は ROUND_DOWN と同じになります。
太字負の場合、丸め動作は ROUND_UP と同じになります。
この丸めモードでは計算値が増加することはありません。
5)ROUND_HALF_UP
「最も近い」数値に向かって四捨五入する、または 2 つの隣接する数値が互いに等距離にある場合は切り上げる丸めモード。
破棄される小数部が 0.5 以上の場合、丸め動作は ROUND_UP と同じになります。それ以外の場合、丸め動作は ROUND_DOWN と同じになります。
これは、ほとんどの人が小学校で習った四捨五入モード (半分に四捨五入) であることに注意してください。
6)ROUND_HALF_DOWN
「最も近い」数値に向かって四捨五入する、または 2 つの隣接する数値が互いに等距離にある場合に切り上げる丸めモード。
切り捨てられる小数部が 0.5 より大きい場合、丸め動作は ROUND_UP と同じになります。それ以外の場合、丸め動作は ROUND_DOWN (切り上げ) と同じになります。
7)ROUND_HALF_EVEN
「最も近い」数値に向かって四捨五入するか、隣接する 2 つの数値までの距離が等しい場合は隣接する偶数に向かって四捨五入します。
破棄された部分の左側の数値が奇数の場合、丸め動作は ROUND_HALF_UP と同じになります。
偶数の場合、丸め動作は ROUND_HALF_DOWN と同じになります。
この丸めモードにより、一連の計算を繰り返すときの累積誤差が最小限に抑えられることに注意してください。
この丸めモードは「バンカーズ丸め」とも呼ばれ、主に米国で使用されています。切り上げて2件で5点。
前の桁が奇数の場合はそれを入力し、そうでない場合は破棄します。
次の例では、小数点以下 1 桁が保持されるため、この丸め方法の結果になります。
1.15>1.2 1.25>1.2
8)ROUND_UNNECESSARY
要求された操作の結果が正確であることをアサートするため、丸めは必要ありません。
正確な結果を取得する演算にこの丸めモードが指定されている場合、ArithmeticException がスローされます。
例: 1÷3 の結果を計算します (結果が無限小数の場合、最後の ROUND_UNNECESSARY はエラーを報告します)
2. サイズを比較する
//前提为a、b均不能为null
BigDecimal a = new BigDecimal("xx");
BigDecimal b = new BigDecimal("xx");
if(a.compareTo(b) == -1){
System.out.println("a小于b");
}
if(a.compareTo(b) == 0){
System.out.println("a等于b");
}
if(a.compareTo(b) == 1){
System.out.println("a大于b");
}
if(a.compareTo(b) > -1){
System.out.println("a大于等于b");
}
if(a.compareTo(b) < 1){
System.out.println("a小于等于b");
}
3. BigDecimal の概要
正確な 10 進数の計算が必要な場合は BigDecimal を使用してください。BigDecimal のパフォーマンスは、特に大規模で複雑な演算を処理する場合、double や float よりも劣ります。したがって、一般的な精度の計算に BigDecimal を使用する必要はありません。パラメーターの型が String であるコンストラクターを使用してみてください。
BigDecimal は不変であり、四則演算が実行されるたびに新しいオブジェクトが生成されるため、加算、減算、乗算、除算を実行する場合は、演算後の値を忘れずに保存してください。
ツールの推奨事項
package com.vivo.ars.util;
import java.math.BigDecimal;
/**
* 用于高精确处理常用的数学运算
*/
public class ArithmeticUtils {
//默认除法运算精度
private static final int DEF_DIV_SCALE = 10;
/**
* 提供精确的加法运算
*
* @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 BigDecimal add(String v1, String v2) {
BigDecimal b1 = new BigDecimal(v1);
BigDecimal b2 = new BigDecimal(v2);
return b1.add(b2);
}
/**
* 提供精确的加法运算
*
* @param v1 被加数
* @param v2 加数
* @param scale 保留scale 位小数
* @return 两个参数的和
*/
public static String add(String v1, String v2, int scale) {
if (scale < 0) {
throw new IllegalArgumentException(
"The scale must be a positive integer or zero");
}
BigDecimal b1 = new BigDecimal(v1);
BigDecimal b2 = new BigDecimal(v2);
return b1.add(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString();
}
/**
* 提供精确的减法运算
*
* @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 BigDecimal sub(String v1, String v2) {
BigDecimal b1 = new BigDecimal(v1);
BigDecimal b2 = new BigDecimal(v2);
return b1.subtract(b2);
}
/**
* 提供精确的减法运算
*
* @param v1 被减数
* @param v2 减数
* @param scale 保留scale 位小数
* @return 两个参数的差
*/
public static String sub(String v1, String v2, int scale) {
if (scale < 0) {
throw new IllegalArgumentException(
"The scale must be a positive integer or zero");
}
BigDecimal b1 = new BigDecimal(v1);
BigDecimal b2 = new BigDecimal(v2);
return b1.subtract(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString();
}
/**
* 提供精确的乘法运算
*
* @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 BigDecimal mul(String v1, String v2) {
BigDecimal b1 = new BigDecimal(v1);
BigDecimal b2 = new BigDecimal(v2);
return b1.multiply(b2);
}
/**
* 提供精确的乘法运算
*
* @param v1 被乘数
* @param v2 乘数
* @param scale 保留scale 位小数
* @return 两个参数的积
*/
public static double mul(double v1, double v2, int scale) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return round(b1.multiply(b2).doubleValue(), scale);
}
/**
* 提供精确的乘法运算
*
* @param v1 被乘数
* @param v2 乘数
* @param scale 保留scale 位小数
* @return 两个参数的积
*/
public static String mul(String v1, String v2, int scale) {
if (scale < 0) {
throw new IllegalArgumentException(
"The scale must be a positive integer or zero");
}
BigDecimal b1 = new BigDecimal(v1);
BigDecimal b2 = new BigDecimal(v2);
return b1.multiply(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString();
}
/**
* 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到
* 小数点以后10位,以后的数字四舍五入
*
* @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();
}
/**
* 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指
* 定精度,以后的数字四舍五入
*
* @param v1 被除数
* @param v2 除数
* @param scale 表示需要精确到小数点以后几位
* @return 两个参数的商
*/
public static String div(String v1, String v2, int scale) {
if (scale < 0) {
throw new IllegalArgumentException("The scale must be a positive integer or zero");
}
BigDecimal b1 = new BigDecimal(v1);
BigDecimal b2 = new BigDecimal(v1);
return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).toString();
}
/**
* 提供精确的小数位四舍五入处理
*
* @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));
return b.setScale(scale, BigDecimal.ROUND_HALF_UP).doubleValue();
}
/**
* 提供精确的小数位四舍五入处理
*
* @param v 需要四舍五入的数字
* @param scale 小数点后保留几位
* @return 四舍五入后的结果
*/
public static String round(String v, int scale) {
if (scale < 0) {
throw new IllegalArgumentException(
"The scale must be a positive integer or zero");
}
BigDecimal b = new BigDecimal(v);
return b.setScale(scale, BigDecimal.ROUND_HALF_UP).toString();
}
/**
* 取余数
*
* @param v1 被除数
* @param v2 除数
* @param scale 小数点后保留几位
* @return 余数
*/
public static String remainder(String v1, String v2, int scale) {
if (scale < 0) {
throw new IllegalArgumentException(
"The scale must be a positive integer or zero");
}
BigDecimal b1 = new BigDecimal(v1);
BigDecimal b2 = new BigDecimal(v2);
return b1.remainder(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString();
}
/**
* 取余数 BigDecimal
*
* @param v1 被除数
* @param v2 除数
* @param scale 小数点后保留几位
* @return 余数
*/
public static BigDecimal remainder(BigDecimal v1, BigDecimal v2, int scale) {
if (scale < 0) {
throw new IllegalArgumentException(
"The scale must be a positive integer or zero");
}
return v1.remainder(v2).setScale(scale, BigDecimal.ROUND_HALF_UP);
}
/**
* 比较大小
*
* @param v1 被比较数
* @param v2 比较数
* @return 如果v1 大于v2 则 返回true 否则false
*/
public static boolean compare(String v1, String v2) {
BigDecimal b1 = new BigDecimal(v1);
BigDecimal b2 = new BigDecimal(v2);
int bj = b1.compareTo(b2);
boolean res;
if (bj > 0)
res = true;
else
res = false;
return res;
}
}
良いことの法則:すべては最終的には良いことになる、それが良いことではない場合、それはまだ終わりではないことを意味します。