Java BigDecimal usage and rounding and formatting specifications (precision data)

Source: Internet
Author: User
Tags mul rounds

The simple floating-point number types in Java float and double are not capable of operation. It's not just Java, it's also a problem in many other programming languages.

What will we see if we compile and run the following program?
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);

}
}

You're not mistaken! The result is indeed

0.060000000000000005
0.5800000000000001
401.49999999999994
1.2329999999999999

Simple floating-point type float and double in Java are not capable of operation. It's not just Java, it's also a problem in many other programming languages. In most cases, the result of the calculation is accurate, but try a few more times (you can do a loop) to try out a similar error. Now we finally understand why we have BCD code.
This problem is quite serious, if you have $9.999999999999, your computer is not going to think you can buy 10 dollars of merchandise.
Special currency types are available in some programming languages to handle this situation, but Java does not. Now let's look at how to solve this problem.

Rounded
Our first reaction was to do rounding. The round method in the Math class cannot be set to retain several decimals, and we can only do this (keep two bits):
Public double round (double value) {
return Math.Round (Value * 100)/100.0;
}

Unfortunately, the above code does not work properly, passing 4.015 to this method it will return 4.01 instead of 4.02, as we saw above
4.015*100=401.49999999999994
So if we're going to do exact rounding, we can't do anything with a simple type.
Java.text.DecimalFormat also does not solve this problem:
System.out.println (New Java.text.DecimalFormat ("0.00"). Format (4.025));
Output is 4.02

BigDecimal
This principle is also mentioned in the book "Effective Java", where float and double can only be used for scientific calculations or engineering calculations, and we use java.math.BigDecimal in business calculations. There are 4 BigDecimal, we do not care about the two that are made with BigInteger, and then there are two of them:

BigDecimal (double val)
Translates a double into a BigDecimal.
BigDecimal (String val)
Translates the String repre sentation of a BigDecimal into a BigDecimal.

The above API brief description is fairly clear, and usually, the one above is easier to use. We may not want to use it, what is the problem? When there is a problem, only to find out which one of the above-mentioned detailed description of the method has such a paragraph:
Note:the results of this constructor can be somewhat unpredictable. One might assume that new BigDecimal (. 1) is exactly equal to. 1, but it's actually equal to. 1000000000000000055511151231 257827021181583404541015625. Because. 1 cannot be represented exactly as a double (or, for that matter, as a bi nary fraction of any finite length). Thus, the Long value that's being passed in to the constructor are not exactly equal to. 1, appearances nonwithstanding.
The (String) constructor, on the other hand, is perfectly predictable:new BigDecimal (". 1") are exactly equal to. 1, as one would expect. Therefore, it is generally recommended and that the (String) constructor being used in preference to this one.
If we need accurate calculation, it is necessary to use string to build BigDecimal! In "effective Java" the example is to use string to build BigDecimal, but the book does not emphasize this point, this may be a small mistake it.

Solution Solutions
Now we can solve this problem, the principle is to use BigDecimal and must use string to build enough.
But imagine, if we're going to do an addition, we need to convert two floating-point numbers to string, then BigDecimal, call the Add method on one of them, pass in another as a parameter, and then transform the result of the operation (BigDecimal) into a floating-point number. Can you endure such a tedious process? Below we provide a tool class arith to simplify the operation. It provides the following static methods, including subtraction and rounding:
public static double Add (Double v1,double v2)
public static double sub (double v1,double v2)
public static double Mul (Double v1,double v2)
public static double div (Double v1,double v2)
public static double div (double v1,double v2,int scale)
public static double round (double v,int scale)
Appendix
Source file Arith.java:
Import Java.math.BigDecimal;

public class Arith {
Default division Operation Precision
private static final int def_div_scale = 10;

This class cannot be instantiated
Private Arith ()
{
;
}
/**
* provides accurate addition operations.
* @param v1 Summand
* @param v2 Addend
* @return of two parameters and
*/
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 ();
}
/**
* Provides accurate subtraction operations.
* @param v1 minuend
* @param v2 meiosis
* @return The difference of two parameters
*/
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 ();
}
/**
* Provides accurate multiplication operations.
* @param v1 by multiplier
* @param v2 Multiplier
* @return The product of two parameters
*/
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 ();
}
/**
* Provide (relative) accurate division operation, when the occurrence of an endless situation, accurate to
* After the decimal point 10 digits, the later numbers are rounded.
* @param v1 Dividend
* @param v2 Divisor
* @return two parameters of the quotient
*/
public static double div (double v1, double v2)
{
Return Div (V1,v2,def_div_scale);
}
/**
* Provide (relative) accurate division operations. When an exception occurs, the scale parameter refers to the
* Fixed precision, after which the numbers are rounded.
* @param v1 Dividend
* @param v2 Divisor
* @param scale indicates the need to be accurate to several decimal places.
* @return two parameters of the quotient
*/
public static double div (double v1, double v2, int scale)
{
if (scale<0)
{
throw new IllegalArgumentException ("The scale must is 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 ();
}
/**
* Provides precise rounding of decimal digits.
* @param v need to be rounded to the number
* Retain several @param scale decimal points
* Results after rounding @return
*/
public static double round (double V, Int. scale)
{
if (scale<0)
{
throw new IllegalArgumentException ("The scale must is 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 ();
}
}

Float,double prone to error, when the accuracy requirements are relatively high, we recommend using decimal to save, decimal in MySQL memory is a string stored, used to define the currency requirements of high precision data. In data migration, float (m,d) is a non-standard definition and should not be used in this way. M is precision and D is the scale.
mysql> CREATE TABLE T1 (C1 float (10,2), C3 decimal (10,2));
Query OK, 0 rows affected (0.02 sec)
mysql> INSERT INTO T1 values (1234567.23, 1234567.23);
Query OK, 1 row affected (0.01 sec)
Mysql> select * from T1;
+------------+------------+
| C1 | C3 |
+------------+------------+
| 1234567.25 | 1234567.23 |
+------------+------------+
1 row in Set (0.02 sec)
mysql> INSERT INTO T1 values (9876543.21, 9876543.12);
Query OK, 1 row Affected (0.00 sec)
Mysql>
Mysql> select * from T1;
+------------+------------+
| C1 | C3 |
+------------+------------+
| 1234567.25 | 1234567.23 |
| 9876543.00 | 9876543.12 |
+------------+------------+
2 rows in Set (0.00 sec)
When you do not define fload, double the precision and scale, the store is stored by the value given, which is related to the OS and the current hardware.
decimal defaults to decimal (10,0)
Because of the error problem, in the program, less use of floating-point to do = comparison, you can do range comparison. If numeric comparisons, it is best to use the decimal type.
In precision, the symbol does not count:
mysql> INSERT INTO T1 values (-98765430.21,-98765430.12);
Query OK, 1 row affected (0.01 sec)
Mysql> select * from T1;
+--------------+--------------+
| C1 | C3 |
+--------------+--------------+
| 1234567.25 | 1234567.23 |
| 9876543.00 | 9876543.12 |
| -98765432.00 | -98765430.12 |
+--------------+--------------+
3 Rows in Set (0.00 sec)
Float accounts for 4 bytes, double is 8 bytes, and Decimail (m,d) accounts for m+2 bytes.

The decimal type can accurately represent very large or very precise decimals. Numbers as large as 1028 (positive or negative) and a number of significant digits up to 28 digits can be stored as a decimal type without sacrificing accuracy. This type is useful for applications that must avoid rounding errors, such as bookkeeping.
Float is a floating-point number, and you cannot specify a decimal place.
Decimal is an exact number and can be specified with precision.
To MySQL 5来 says the maximum of P in decimal (p,s) is 65,s maximum is 30
The decimal data type can store up to 38 digits, which stores an accurate (accurate) representation of a number without storing the approximate value of the value.
When data values must be stored exactly as specified, a decimal data type with decimals can be used to store numbers.
The float and real data types are referred to as approximate data types. Exact values are not stored. When an exact number state is required, such as in a financial application, these data types are not used in operations that require rounding, or in an equivalence check. This is when you want to use integer, Decimal, Money, or smallmone data types.
In the WHERE clause search condition (especially the = and <> operators), avoid using the float or the real column. It is best to limit the use of float and real columns for > or < comparisons.


BigDecimal Rounding Mode Description:
Rounding mode is inside Java.math.RoundingMode:
Roundingmode.ceiling: Rounding mode rounded to the positive infinity direction. If the result is positive, the rounding behavior is similar to Roundingmode.up, and if the result is negative, the rounding behavior is similar to Roundingmode.down. Note that this rounding mode always does not reduce the calculated value
Enter number rounds a number to one digit using ceiling rounding mode
5.56
2.53
1.12
1.01
-1.0-1
-1.1-1
-1.6-1
-2.5-2
-5.5-5
Roundingmode.down: Rounding mode rounded in 0 direction. Do not add 1 (that is, truncated) to the number preceding the Discard section. Note that this rounding mode always does not increase the absolute value of calculated values
Entering a number rounds a number to one digit using the down rounding mode
5.55
2.52
1.11
-1.0-1
-1.6-1
-2.5-2
-5.5-5
Roundingmode.floor: Rounding mode rounded to a negative infinity direction. If the result is positive, the rounding behavior is similar to Roundingmode.down, and if the result is negative, the rounding behavior is similar to Roundingmode.up. Note that this rounding mode always does not increase the calculated value
Enter a number rounds the input number to one using floor rounding mode
5.55
2.32
1.61
1.01
-1.1-2
-2.5-3
-5.5-6
Roundingmode.half_down: Rounding mode rounded to the nearest number direction, rounded down if the distance to the two adjacent digits is equal. If part > 0.5 is discarded, the rounding behavior is the same as roundingmode.up; otherwise the rounding behavior is the same as Roundingmode.down
The input number is rounded to one using the Half_down input mode
5.55
2.52
1.62
1.01
-1.1-1
-1.6-2
-2.5-2
-5.5-5
Roundingmode.half_even: Rounding mode rounded to the nearest number direction, rounded to adjacent even if the distance from the two adjacent digits is equal. If the left part of the discard number is odd, the rounding behavior is the same as roundingmode.half_up, and if even, the rounding behavior is the same as Roundingmode.half_down. Note that this rounding mode minimizes cumulative errors on statistics when a series of calculations are repeated. This rounding mode is also known as the Banker rounding method, mainly used in the United States. This rounding pattern is similar to the rounding policy used by the float and double algorithms in Java
Enter a number use Half_even rounding mode to give the input a
5.56
2.52
1.62
1.11
-1.0-1
-1.6-2
-2.5-2
-5.5-6
ROUNDINGMODE.HALF_UP: Rounding mode rounded to the nearest number direction, rounded up if the distance to the two adjacent digits is equal. If part >= 0.5 is discarded, the rounding behavior is the same as roundingmode.up, otherwise the rounding behavior is the same as Roundingmode.down. Note that this rounding mode is usually rounded up in the school
The input number is rounded to one digit using HALF_UP rounding mode
5.56
2.53
1.62
1.01
-1.1-1
-1.6-2
-2.5-3
-5.5-6
Roundingmode.unnecessary: The rounding mode used to assert that the requested operation has a precise result, so no rounding is required. If this rounding mode is specified for operations that produce exact results, the ArithmeticException is thrown
Enter numbers using unnecessary mode
5.5 Throwing ArithmeticException
2.5 Throwing ArithmeticException
1.6 Throwing ArithmeticException
1.01
-1.0-1.0
-1.1 Throw ArithmeticException
-1.6 Throw ArithmeticException
-2.5 Throw ArithmeticException
-5.5 Throw ArithmeticException
Roundingmode.up: Rounding mode that is rounded away from the 0 direction. Always add 1 to the number preceding the part that is not 0 discarded. Note that this rounding mode always does not reduce the absolute value of calculated values
Enter number rounds the input number to one digit using up rounding mode
5.56
1.62
1.12
1.01
-1.1-2
-1.6-2
-2.5-3
-5.4-6
--[$] Sample code:--

Import Java.math.BigDecimal;
Import Java.text.DecimalFormat;
/**
* Formatting operations using rounding mode
**/
public class Doubleformat {
public static void Main (String args[]) {
Doubleformat format = new Doubleformat ();
System.out. println (Format.doubleoutput (12.345, 2));
System.out. println (Format.roundnumber (12.335, 2));
}
Public String doubleoutput (double V,integer num) {
if (v = = double.valueof (v). Intvalue ()) {
return double.valueof (v). Intvalue () + "";
}else {
BigDecimal B = New BigDecimal (double.tostring (v));
Return B.setscale (NUM,BIGDECIMAL.ROUND_HALF_UP). toString ();
}
}
Public String roundnumber (double v,int num) {
String fmtstring = "0000000000000000"; 16bit
fmtstring = num>0? "0." + fmtstring.substring (0,num): "0";
DecimalFormat Dformat = new DecimalFormat (fmtstring);
return Dformat.format (v);
}
}
The output of this piece of code is:
12.35
12.34

Java BigDecimal usage and rounding and formatting specifications (precision data)

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.