android is not in pit three: Float loses accuracy
Preface:
Testing: You mean, how do you correct the error, how do you let me test it! ____________
Faced with the roar of testing, go quickly to the gray inspection code. Yeah, finally test for loops several times before you find out, Dayday! ____________ How could this happen? Isn't this a pit?
Back when the development city, basically all String to use BigDecimal for precise calculation
Of course, look at the test. How float loses accuracy?
public class Test_1 { public static void main(String[] args) { System.out.println(0.06+0.01); System.out.println(1.0-0.42); System.out.println(4.015*100); System.out.println(303.1/1000); } }
The results are as follows. 0.06999999999999999 0.5800000000000001 401.49999999999994 0.30310000000000004
You think you are wrong, but the result is that. What's the problem? The reason is that our computer is binary. Floating-point numbers cannot be represented precisely in binary. Our CPU indicates that floating-point numbers are composed of two parts: exponential and tail numbers. Such a representation usually loses some accuracy, and some floating-point operations also produce certain errors. For example, the binary representation of 2.4 is not exactly 2.4. Instead, the closest binary representation is 2.39999999999999. Floating point values are actually calculated by a specific mathematical formula.
In fact, Java float can only be used for scientific or engineering calculations. In most commercial calculations, the java.math.BigDecimal class is generally used for accurate calculations.
Well, here's a big pill tool.
public class DecimalUtil { /** * Money addition */ public static String add(String v1, String v2) { BigDecimal b1 = new BigDecimal(v1); BigDecimal b2 = new BigDecimal(v2); return b1.add(b2).toString(); } /** * Money multiplication */ public static String multiply(String v1, String v2) { BigDecimal b1 = new BigDecimal(v1); BigDecimal b2 = new BigDecimal(v2); return b1.multiply(b2).toString(); } /** * multiplication * * @param v1 multiplier * @param v2 Multiplier * @param scale Reserved digits of decimal points */ public static String multiplyWithScale(String v1, String v2, int scale) { BigDecimal b1 = new BigDecimal(v1); BigDecimal b2 = new BigDecimal(v2); BigDecimal result = b1.multiply(b2); result = result.setScale(scale); return result.toString(); } /** * Money Division */ public static String divide(String v1, String v2) { BigDecimal b1 = new BigDecimal(v1); BigDecimal b2 = new BigDecimal(v2); return b1.divide(b2).toString(); } /** * If an infinite circular decimal is generated in addition to a constant number, then an exception will be thrown. The solution is to limit the number of decimal places after the decimal point. * * @param v2 Decimal mode, DOWN, means no rounding directly. Refer to {@link Rounding Mode} */ public static String divideWithRoundingDown(String v1, String v2) { return divideWithRoundingMode(v1, v2, RoundingMode.DOWN); } /** Choose decimal processing */ public static String divideWithRoundingMode(String v1, String v2, RoundingMode roundingMode) { return divideWithRoundingModeAndScale(v1, v2, RoundingMode.DOWN, 0); } /** * Select the post-decimal part and reserve several decimal places * * @param v1 Divisor * @param v2 Dividend * @param roundingMode Decimal processing mode * @param scale Retain a few */ public static String divideWithRoundingModeAndScale(String v1, String v2, RoundingMode roundingMode, int scale) { BigDecimal b1 = new BigDecimal(v1); BigDecimal b2 = new BigDecimal(v2); return b1.divide(b2, scale, roundingMode).toString(); } /** * Money subtraction */ public static String subtract(String v1, String v2) { BigDecimal b1 = new BigDecimal(v1); BigDecimal b2 = new BigDecimal(v2); return b1.subtract(b2).toString(); } }
Usage method:
Multiplication:
String countIntegral = DecimalUtil.multiply(integral, num);
Addition:
String selectedMoney = DecimalUtil.add(selectedMoney, countMoney);
Concluding remarks: Finally, remember that the incoming parameter cannot be empty, that is, the initial value should be 0, String num="0", otherwise the error will be reported.