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