The holes in arithmetic in Java

Source: Internet
Author: User

The use of Java development for many years, feel their own level is also rising, but the Java has never changed, and any small corner of Java, can take my abuse of the pieces, but helpless to rely on Java to eat, but also to continue to use the face of Tian.
Talk about the recent problems, then the new job belongs to the internet finance, so it involves a lot of money calculation, money calculation on the number of strict requirements, as a careless and arrogant Java programmer, has not taken this as a matter, and then again by Java amputated again.
Let's take a look at some of the little holes in Java that arithmetic.

Mathematical calculation, it is unavoidable to think of int long double this data type, but double in the procedural world since ancient times, on the surface of the math as a decimal, actually completely different. Here's a tour:

Double the PitAddition Pits
double d1 = 0.1;d1 += 0.1;d1 += 0.1;d1 += 0.1;d1 += 0.1;d1 += 0.1;d1 += 0.1;d1 += 0.1;d1 += 0.1; // 连着加了8次System.out.println(d1);  

0.8999999999999999

It's not what we expected. 0.9

Subtraction Pits
double d1 = 1.0;double d2 = 0.1;d1 -= d2;d1 -= d2;d1 -= d2;d1 -= d2;d1 -= d2;d1 -= d2;d1 -= d2;d1 -= d2;d1 -= d2; // 连着减了9次0.1System.out.println(d1);  

0.10000000000000014

It's not what we expected. 0.1

Multiplication Pits
double d1 = 123213.0;d1 *= 0.35;System.out.println(d1);

43124.549999999996

It's not what we expected. 43124.55

Division Pits
double result = 11.4/12;System.out.println(result);  

0.9500000000000001

It's not what we expected. 0.95

* * This shows that if you need to subtraction arithmetic money, you must not use double the type, the result is always out of your expectation. **

Large number to string pit

Try individual, mathematical operations, always use a larger number bar, try a tens of millions of numbers it:

double bigValue = 12345678.9;System.out.println(bigValue);  

1.23456789E7

Turned into a scientific notation ... This is not a format for people to look at.
So, if you want to display a large floating-point number, use DecimalFormat to format it yourself.

Except 0 pits

From elementary school math knows not to divide by 0 to see the performance of double:

result = 1.0/0.0;System.out.println(result);result = 0.0/0.0;System.out.println(result);  

Infinity
NaN

It really can't be divided by 0, but the result is beyond your expectation, yes, double provides several ways to check:
Double.isInfinite(double)Whether it is a infinite number
Double.isFinite(double)Is there a finite number of
Double.isNaN(double)Whether this is the number

Nan = Not-a-number, two Nan's number comparison, unexpectedly unequal, is not more and more interesting.

Compare whether the pits are equal
System.out.println(1.1 == 1.1? "true": "false");System.out.println(1.1 == 1.100000000000001? "true": "false");System.out.println(1.1 == 1.10000000000000009? "true": "false");  

True
False
True

It's unexpected.

Summarize:
In the case of money-related operations, you must not use the double type, or a careless will make you look good.
So what double type of use is appropriate? Java provides a named BigDecimal object, specifically for computing use, but the bigdecimal is not so easy to use, improper, or will be burst Xiang.

Attached: The floating-point number in the computer to indicate how the double is so bizarre.

BigDecimal's pit.Pit 1: Instantiating objects
BigDecimal num = new BigDecimal(0.3);System.out.println(num);

0.299999999999999988897769753748434595763683319091796875

This is not a game, in other ways:

BigDecimal num = new BigDecimal("0.3");System.out.println(num);

0.3

That's all for you.

Pit 2: Division
BigDecimal d = BigDecimal.ONE;  d.divide(new BigDecimal("3"));  

Exception in thread "main" java.lang.arithmeticexception:non-terminating decimal expansion; No exact representable decimal result.

What the hell is this? For the hair of an abnormal ah ...
Okay, keep two decimal places and try.

BigDecimal d = BigDecimal.ONE;  d.divide(new BigDecimal("3"), 2, BigDecimal.ROUND_HALF_UP);System.out.println(d);

1

Hey, why not 0.33, the number has not changed?
The reason is: The BigDecimal is immutable, return the new object after each operation, and then change:

BigDecimal d = BigDecimal.ONE;  d = d.divide(new BigDecimal("3"), 2, BigDecimal.ROUND_HALF_UP);System.out.println(d);

0.33

Take a breath, finally.

Pit 3: The fractional part rounds the pit of the Carry

Rounding, what can be said? It's really got to be said, rounding carry can be see RoundingMode enumeration, which contains various rounding carry, need to read carefully oh, otherwise a foot a pit.
This is not about rounding the type of carry, but rather about the method provided in BigDecimal:
num.setScale(2, BigDecimal.ROUND_HALF_EVEN);
num.setScale(2, RoundingMode.HALF_EVEN);
What's the difference between Bigdecimal.round_half_even and Roungingmode.half_even in these two things?
The answer is no difference, the same use, Roungingmode enumeration is JDK1.5 Later, Java support enumeration type after adding, there is a oldmode, which is saved is the corresponding constant in BigDecimal.

Pit 4: Pit retaining number of bits

Leave the fractional part N-bit This is a very common operation that was used when a double was previously applied:
1. Multiply by 10 of the N-th square
2. Round
3. Divide by 10 by the N-th square
In this way, the BigDecimal is bound to provide a rounding method and is simple to use:

BigDecimal num = new BigDecimal("1.2345678");num = num.setScale(2, BigDecimal.ROUND_HALF_EVEN);System.out.println(num);  

1.23

Things would have been easy to end, but the eyes were cheap and glanced elsewhere, MathContext what was this? It seems to be used for rounding, try:

MathContext ctx = new MathContext(2);num = new BigDecimal("12.34");num1 = new BigDecimal("56.78");num = num.multiply(num1, ctx);  

7.0E+2

No, we want to see 700.67 it, change it.

MathContext ctx = new MathContext(3);

701

MathContext ctx = new MathContext(4);

700.7

MathContext ctx = new MathContext(5);

700.67

MathContext ctx = new MathContext(6);

700.665

See, this number is the number of digits, not the number of digits after the decimal point.

Pit 5: Comparison of equal pits
num = new BigDecimal("1");num1 = new BigDecimal("1.0");System.out.println(num.equals(num1)); // 竟然不相等呀System.out.println(num.compareTo(num1)); // 0   

False
0

The equals of BigDecimal is greatly unexpected, but it is not possible to use the Equals method to compare the size of the two bigdecimal. Fortunately CompareTo still easy to use ...

The holes in arithmetic in Java

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.