Java floating point Exact Calculation

Source: Internet
Author: User

(1) Precise Floating Point Calculation
There has always been a problem in the Three-flow Integration Project of Shengli Oilfield, that is, the amount of materials and the actual amount calculated in each report must be a fraction of the money, which is different from the actual amount, this makes customers feel uncomfortable because we use the Double Floating Point Type of Java to define the material amount, and we often need to perform some operations in report statistics, however, the calculation of Floating Point Numbers (double and float) in Java is not accurate. See the following example:

  1. System. Out. println (0.05 + 0.01 );
  2. System. Out. println (1.0-0.42 );
  3. System. Out. println (4.015*100 );
  4. System. Out. println (123.3/100 );

Copy code

What is your expected output? The actual output is as follows:

  1. 0.060000000000000005
  2. 0.5800000000000001
  3. 401.49999999999994
  4. 1.2329999999999999

Copy code

This problem is very serious. If you have 123.3 yuan to buy goods, but the computer thinks you only have 123.29999999999999 yuan, the money is not enough, and the computer refuses to trade.
(2) Rounding
Can it be rounded in? Of course we can. In our habits, we will think like this, But rounding means an error, and commercial operations may mean an error. At the same time, Java does not provide a rounding method that retains the specified number of digits, only one math is provided. round (double D) and math. the round (float f) method returns the long integer and integer values respectively. The round method cannot be set to retain a few decimal places. We can only keep two digits as follows ):

  1. Public double round (double value ){
  2. Return math. Round (value * 100)/100.0;
  3. }

Copy code

But unfortunately, the above Code does not work normally. If you pass 4.015 to this method, it will return 4.01 instead of 4.02, as shown in the preceding figure.

  1. 4.015*100 = 401.49999999999994

Copy code

Therefore, this method cannot meet our requirements for accurate rounding.
Another method is to use Java. text. decimalformat, but there are also problems. The format adopts the round_half_down round mode (the round mode is described below). For example, if 4.025 is reserved, the two decimal places will be 4.02, because. 025 distance from "Nearest Neighbor "(. 02 and. 03) the length is equal, and the rounding down is. 02. If it is 4.0251, the two decimal places reserved are 4.03.

  1. System. Out. println (New java. Text. decimalformat ("0.00"). Format (4.025 ));
  2. System. Out. println (New java. Text. decimalformat ("0.00"). Format (4.0251 ));

Copy code

The output is

  1. 4.02
  2. 4.03

Copy code

(3) floating point output (Scientific note)
If the Java floating point value is greater than 9999999.0, it is automatically converted to scientific notation. Let's look at the following example:

  1. System. Out. println (999999999.04 );
  2. System. Out. println (99999999.04 );
  3. System. Out. println (10000000.01 );
  4. System. Out. println (9999999.04 );

Copy code

The output result is as follows:

  1. 9.9999999904e8
  2. 9.999999904e7
  3. 1.20.00001e7
  4. 9999999.04

Copy code

However, sometimes we do not need to use the scientific notation to convert it into a string, and cannot directly use tostring () or other methods to convert it.
About bigdecimal

Bigdecimal is a constant, any-precision signed decimal number object provided by Java. It provides four constructors, two of which are constructed using biginteger, which we don't care about here, we will focus on the two constructors constructed with double and string (for more information about biginteger, see j2se API documentation ).

  1. Bigdecimal (double Val)
  2. Translates a double into a bigdecimal.
  3. Bigdecimal (string Val)
  4. Translates the string representation of a bigdecimal into a bigdecimal.

Copy code

Bigdecimal (double) refers to the construction of a double type decimal number as a bigdecimal object instance.
Bigdecimal (string) is to construct a bigdecimal object represented by string as a bigdecimal object instance.
In practice, we define floating point numbers as double or float, but the bigdecimal (double) API document has the following sentence:
Note: The results of this constructor can be somewhat unpredictable. one might assume that new bigdecimal (. 1) is exactly equal. 1, but it is actually equal. 10000000000000000555111512312578 27021181583404541015625. this is so because
. 1 cannot be represented exactly as a double (or, for that matter, as a binary fraction of any finite length ). thus, the long value that is being passed in to the constructor is not exactly equal. 1, appearances notwithstanding.
The (string) constructor, on the other hand, is perfectly predictable: New bigdecimal (". 1 ") is exactly equal. 1, as one wocould CT. therefore, it is generally recommended that the (string) constructor be used in preference to this one
The following is a simple explanation of this passage:
Note: The constructor may have unpredictable results. Someone may imagine new bigdecimal (. 1) equal. 1 is correct, but it is actually equal. 1000000000000000055511151231257827021181583404541015625, that's why. 1 cannot be exactly represented by a double. Therefore, the long value put into the constructor is not exactly equal. 1, although the appearance looks equal.
However, the (string) constructor is completely predictable. New bigdecimal (". 1 ") exact equals as expected. 1. Therefore, the (string) constructor is recommended first.
See the following results:

  1. System. Out. println (New bigdecimal (123456789.02). tostring ());
  2. System. Out. println (New bigdecimal ("123456789.02"). tostring ());

Copy code

Output:

  1. 123456789.01999999582767486572265625
  2. 123456789.02

Copy code

Now we know that if exact calculation is required, you must use string to create bigdecimal!
Implementation Scheme

Now we know how to solve this problem. In principle, we use the bigdecimal (string) constructor. We recommend that you use data involving floating point numbers such as amounts in commercial application development, all are defined as string, which can be defined as character fields in the database. When you need to use this data for computation, use bigdecimal (string) to construct a bigdecimal object for computation to ensure accurate data computation. It also avoids the emergence of scientific notation. If scientific notation is not a burden in applications, you can consider defining it as a floating point type.

Here we provide a tool class that defines the addition, subtraction, multiplication, division, and rounding of floating point numbers. For reference.
Source File mathextend. Java:

  1. Import java. Math. bigdecimal;
  2. Public class mathextend
  3. {
  4. // Default division operation precision
  5. Private Static final int default_div_scale = 10;
  6. /**
  7. * Provides precise addition operations.
  8. * @ Param V1
  9. * @ Param v2
  10. * @ Return the sum of the two parameters
  11. */
  12. Public static double add (double V1, double V2)
  13. {
  14. Bigdecimal b1 = new bigdecimal (double. tostring (V1 ));
  15. Bigdecimal b2 = new bigdecimal (double. tostring (V2 ));
  16. Return b1.add (B2). doublevalue ();
  17. }
  18. /**
  19. * Provides accurate addition operations
  20. * @ Param V1
  21. * @ Param v2
  22. * @ Return mathematical Addition of two parameters, returned in string format
  23. */
  24. Public static string add (string V1, string V2)
  25. {
  26. Bigdecimal b1 = new bigdecimal (V1 );
  27. Bigdecimal b2 = new bigdecimal (V2 );
  28. Return b1.add (B2). tostring ();
  29. }
  30. /**
  31. * Provides precise subtraction operations.
  32. * @ Param V1
  33. * @ Param v2
  34. * @ Return Difference Between Two Parameters
  35. */
  36. Public static double subtract (double V1, double V2)
  37. {
  38. Bigdecimal b1 = new bigdecimal (double. tostring (V1 ));
  39. Bigdecimal b2 = new bigdecimal (double. tostring (V2 ));
  40. Return b1.subtract (B2). doublevalue ();
  41. }
  42. /**
  43. * Provides precise subtraction.
  44. * @ Param V1
  45. * @ Param v2
  46. * @ Return: returns the mathematical difference between two parameters in string format.
  47. */
  48. Public static string subtract (string V1, string V2)
  49. {
  50. Bigdecimal b1 = new bigdecimal (V1 );
  51. Bigdecimal b2 = new bigdecimal (V2 );
  52. Return b1.subtract (B2). tostring ();
  53. }
  54. /**
  55. * Provides precise multiplication.
  56. * @ Param V1
  57. * @ Param v2
  58. * @ Return the product of two parameters
  59. */
  60. Public static double multiply (double V1, double V2)
  61. {
  62. Bigdecimal b1 = new bigdecimal (double. tostring (V1 ));
  63. Bigdecimal b2 = new bigdecimal (double. tostring (V2 ));
  64. Return b1.multiply (B2). doublevalue ();
  65. }
  66. /**
  67. * Accurate Multiplication
  68. * @ Param V1
  69. * @ Param v2
  70. * @ Return mathematical product of the two parameters, returned in string format
  71. */
  72. Public static string multiply (string V1, string V2)
  73. {
  74. Bigdecimal b1 = new bigdecimal (V1 );
  75. Bigdecimal b2 = new bigdecimal (V2 );
  76. Return b1.multiply (B2). tostring ();
  77. }
  78. /**
  79. * Provides (relatively) accurate Division operations, accurate
  80. * 10 digits after the decimal point, rounded to the next digit. round_half_even is used for rounding.
  81. * @ Param V1
  82. * @ Param v2
  83. * @ Return parameter vendors
  84. */
  85. Public static double divide (double V1, double V2)
  86. {
  87. Return divide (V1, V2, default_div_scale );
  88. }
  89. /**
  90. * Provides (relatively) accurate Division operations. In case of division, the scale parameter indicates
  91. * Set the precision. The number is rounded down. Round_half_even is used for rounding.
  92. * @ Param V1
  93. * @ Param v2
  94. * @ Param scale indicates the number of digits after the decimal point.
  95. * @ Return parameter vendors
  96. */
  97. Public static double divide (double V1, double V2, int scale)
  98. {
  99. Return divide (V1, V2, scale, bigdecimal. round_half_even );
  100. }
  101. /**
  102. * Provides (relatively) accurate Division operations. In case of division, the scale parameter indicates
  103. * Set the precision. The number is rounded down. The rounding mode is specified by the user.
  104. * @ Param V1
  105. * @ Param v2
  106. * @ Param scale indicates the number of digits after the decimal point.
  107. * @ Param round_mode indicates the rounding mode specified by the user.
  108. * @ Return parameter vendors
  109. */
  110. Public static double divide (double V1, double V2, int scale, int round_mode ){
  111. If (scale <0)
  112. {
  113. Throw new illegalargumentexception ("the scale must be a positive integer or zero ");
  114. }
  115. Bigdecimal b1 = new bigdecimal (double. tostring (V1 ));
  116. Bigdecimal b2 = new bigdecimal (double. tostring (V2 ));
  117. Return b1.divide (B2, scale, round_mode). doublevalue ();
  118. }
  119. /**
  120. * Provides (relatively) accurate Division operations, accurate
  121. * 10 digits after the decimal point, rounded to the next digit. round_half_even is used for rounding.
  122. * @ Param V1
  123. * @ Param v2
  124. * @ Return refers to the operator of two parameters, which are returned in string format.
  125. */
  126. Public static string divide (string V1, string V2)
  127. {
  128. Return divide (V1, V2, default_div_scale );
  129. }
  130. /**
  131. * Provides (relatively) accurate Division operations. In case of division, the scale parameter indicates
  132. * Set the precision. The number is rounded down. Round_half_even is used for rounding.
  133. * @ Param V1
  134. * @ Param v2
  135. * @ Param scale indicates the number of digits after the decimal point.
  136. * @ Return refers to the operator of two parameters, which are returned in string format.
  137. */
  138. Public static string divide (string V1, string V2, int scale)
  139. {
  140. Return divide (V1, V2, default_div_scale, bigdecimal. round_half_even );
  141. }
  142. /**
  143. * Provides (relatively) accurate Division operations. In case of division, the scale parameter indicates
  144. * Set the precision. The number is rounded down. The rounding mode is specified by the user.
  145. * @ Param V1
  146. * @ Param v2
  147. * @ Param scale indicates the number of digits after the decimal point.
  148. * @ Param round_mode indicates the rounding mode specified by the user.
  149. * @ Return refers to the operator of two parameters, which are returned in string format.
  150. */
  151. Public static string divide (string V1, string V2, int scale, int round_mode)
  152. {
  153. If (scale <0)
  154. {
  155. Throw new illegalargumentexception ("the scale must be a positive integer or zero ");
  156. }
  157. Bigdecimal b1 = new bigdecimal (V1 );
  158. Bigdecimal b2 = new bigdecimal (V2 );
  159. Return b1.divide (B2, scale, round_mode). tostring ();
  160. }
  161. /**
  162. * Provides precise decimal point rounding. The rounding mode adopts round_half_even.
  163. * @ Param V refers to the number rounded up.
  164. * @ Param scale: number of digits after the decimal point
  165. * @ Return returns the result after rounding.
  166. */
  167. Public static double round (Double V, int scale)
  168. {
  169. Return round (v, scale, bigdecimal. round_half_even );
  170. }
  171. /**
  172. * Provides precise rounding of decimal places.
  173. * @ Param V refers to the number rounded up.
  174. * @ Param scale: number of digits after the decimal point
  175. * @ Param round_mode the specified rounding mode
  176. * @ Return returns the result after rounding.
  177. */
  178. Public static double round (Double V, int scale, int round_mode)
  179. {
  180. If (scale <0)
  181. {
  182. Throw new illegalargumentexception ("the scale must be a positive integer or zero ");
  183. }
  184. Bigdecimal B = new bigdecimal (double. tostring (V ));
  185. Return B. setscale (scale, round_mode). doublevalue ();
  186. }
  187. /**
  188. * Provides precise decimal point rounding. The rounding mode adopts round_half_even.
  189. * @ Param V refers to the number rounded up.
  190. * @ Param scale: number of digits after the decimal point
  191. * @ Return returns the result after rounding, in string format
  192. */
  193. Public static string round (string V, int scale)
  194. {
  195. Return round (v, scale, bigdecimal. round_half_even );
  196. }
  197. /**
  198. * Provides precise rounding of decimal places.
  199. * @ Param V refers to the number rounded up.
  200. * @ Param scale: number of digits after the decimal point
  201. * @ Param round_mode the specified rounding mode
  202. * @ Return returns the result after rounding, in string format
  203. */
  204. Public static string round (string V, int scale, int round_mode)
  205. {
  206. If (scale <0)
  207. {
  208. Throw new illegalargumentexception ("the scale must be a positive integer or zero ");
  209. }
  210. Bigdecimal B = new bigdecimal (v );
  211. Return B. setscale (scale, round_mode). tostring ();
  212. }
  213. }

Copy code

Introduction to the bigdecimal round mode:

Bigdecimal defines the rounding mode, which is used only when Division operations or rounding are performed. For more information, see j2se API documentation.
Static int
Round_ceiling
Rounding mode to Round towards positive infinity.
Round to positive infinity
Static int
Round_down
Rounding mode to Round towards zero.
Round to zero
Static int
Round_floor
Rounding mode to Round towards negative infinity.
Round to negative infinity
Static int
Round_half_down
Rounding mode to Round towards "Nearest Neighbor" unless both neighbors are equidistant, in which case round down.
Round to the nearest side, unless the two sides (distance) are equal. If so, round down. For example, 1.55 retains a decimal number and returns 1.5.
Static int
Round_half_even
Rounding mode to Round towards the "Nearest Neighbor" unless both neighbors are equidistant, in which case, Round towards the even neighbor.
Round to the nearest side (distance), unless the two sides (distance) are equal. If so, use round_half_up if the reserved digits are odd. If the reserved digits are even, use round_half_down.
Static int
Round_half_up
Rounding mode to Round towards "Nearest Neighbor" unless both neighbors are equidistant, in which case round up.
Round to the nearest side (distance), unless the two sides (distance) are equal, if so, round up, 1.55 retains a decimal number and returns 1.6
Static int
Round_unnecessary
Rounding mode to assert that the requested operation has an exact result, hence no rounding is necessary.
The calculation result is accurate, and the rounding mode is not required.
Static int
Round_up
Rounding mode to round away from zero.
Round to the direction away from 0

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.