2013年11月1日星期五

Java floating-point operations a strange phenomenon: 0.01 +0.09 not equal to 0.1 ? !

public class Test
{
public static void main (String [] args)
{
double x = 0.01;
double y = 0.09;
System.out.println (x + y);
}
}

Why output is 0.09999999999999999 instead of 0.1 ah ?
The strange thing is when x, y to float , the result is equal to 0.1 , and
Even more surprising is that if the x, y , respectively, 0.01 and 0.04 to float , in addition , the result is actually 0.049999997 ,
inexact floating point behind this principle in the end what is it ?

more bizarre is that this code into C #, running out of the result is 0.1

    class Test
    {
        static void Main()
        {
             double x = 0.01;
             double y = 0.09;
             Console.WriteLine(x + y);
             Console.ReadKey();
        }
    }

------ Solution ------------------------------------- -------
first point , you have to clear the float java inside 32 on 0.1 in-memory representation which is inaccurate , not you understand it 100% accurate , to abandon this concept , resulting in the the reason is simple to understand errors in 32 of the float 's limited ability to express and computer binary because of it, down to say is also very complicated. Under
Generally speaking , float 0.1 is 001111011 10011001100110011001101 binary form , according to the sign bit in terms of the values ​​expressed in decimal precision should be calculated by multiplying two negative 27 110011001100110011001101 power , the actual value is 0.100000001490116119384765625
This gives rise to the actual error
This error is nothing minor impact on our lives , but for scientific computing and banking areas such application or be fatal , so use Java banks, and scientific computing will be used to improve the accuracy java.math.BigDecimal , otherwise extremely serious consequences .

reference I have answered the CSDN posts http://topic.csdn.net/u/20110804/00/15380122-33a1-474a-9b7f-3e90a000f0a8.html
------ Solution - -------------------------------------------
this involves floating points structures ( sign bit, exponent , mantissa part ) , as well as normalized and non- normalized representation of representation .
This is not explained in detail , LZ can access relevant information
There are several knowledge points :
1. floating computer base is 2 .
2. exponent part with offset (float was 127, double of 1023 )
3. normalized left of the decimal representation must be 1. ( binary number )
4.float type accounted for a sign bit , 8 exponent part of the total , accounting for 23 mantissa ( because of normalization that is a certain left of the decimal , so the actual 24 -bit precision )
5.double type accounted for a sign bit , exponent part accounted for 11 , accounting for 52 mantissa ( because of normalization that is a certain left of the decimal , so the actual 53 -bit precision )

look at an example float 0.6 bar :
first step, decimal to binary :
0.6 binary representation ( by 2 rounded , order means ) :
.1001 1001 1001 1001 1001 1001 1001 ... infinite loop .

The second step, calculating mantissa part :
to .1001 1001 1001 1,001,100,110,011,001 ... normalized representation ( decimal point to the right of the first non-zero book ) is this:
1.001 1001 1001 1001 1001 1001 1001 ..., right up one .
expressed as normalized as a certain number of digits left to make this a discard , and retain float mantissa can represent the 23 , the final mantissa parts are:
001 1001 1001 1001 1001 1001

The third step is to calculate exponent part :
Because when calculating mantissa of a right , the equivalent of multiplying two negative one times, so index is -1, plus float offset 127 , the final index is 126 ,
binary representation 01111110

fourth step , the symbol sections:
0.6 is positive, the sign bit is 0

final 0.6 in the computer indicates that :

sign bit exponent mantissa
0 0111 1110 001 1001 1001 1001 1001 1001
---------------------------------------------- ----------------
We then calculated from this binary decimal : ( 2 times * exponent mantissa )
sign bit 0 - > is positive
index 01111110 : 126 , minus the offset 127 , the result is -1.
mantissa 0,011,001,100,110,011,001 1001: normalized left of the decimal when people lost a one , now add :
1.001 1001 1001 1001 1001 1001, converted to decimal is :
1 * 2 ^ 0 + 1 * 2 ^ -3 + 1 * 2 ^ -4 + ..... = 1.19999992847442626953125
1.19999992847442626953125 * 2 ^ -1 = 0.599999964237213134765625
So the end result is an infinitely close to 0.6 and can not be represented exactly 0.6

--------------------------------------
In fact, I this post has already replied to the < br> ------ For reference only ---------------------------------------
JAVA decimal ( floating point , DOUBLE) will lose accuracy . Use precise calculation to use BigDecimal
------ For reference only ------------------------------- --------

         //java是一门很怪异的语言
System.out.println(1.0/0);//Infinity
System.out.println(1/0);// java.lang.ArithmeticException: 


------ For reference only ------------------------ ---------------
many floats are not accurately represented , normal
------ For reference only ------- --------------------------------
Yes, it used bigdecimal

------ For reference only ---------------------------------- -----
this is normal
The details of proper input conversion from a Unicode string representation of a floating-point number to the internal IEEE 754 binary floating- point representation are described for the methods valueOf of class Float and class Double of the package java.lang.
reason
------ For reference only --------------------------------- ------
float, can not be directly used to calculate , will lose accuracy .
------ For reference only -------------------------------------- -
composition principle is not strange to find this book to look up
------ For reference only ----------------------- ----------------

this nice
------ For reference only ------------- --------------------------


agreed Oh learned

------ For reference only ---------------------------------- -----
would also be right !
public class DoubleClass {
public static void main (String [] args) {
double x = 0.09;
double y = 0.01;
System.out.println ((float) (x + y));
}
}
------ For reference only --------------------------------- ------
because java is not going to represent 1/10 of this value , you can use this type of bigdecimal try .
------ For reference only ------ ---------------------------------
precision problems with BigDecimal
------ For reference only ---------------------------------------
See "Java Solutions confusion "
------ For reference only ------------------------------------ ---
converted into binary turn back the middle inevitable errors
------ For reference only --------------------- ------------------
this fact is well understood, there is not an accurate count in the binary representation . Like 1/ 3 if the three hex is three negative once, but the same can not be expressed in decimal .
------ For reference only -------------------------------------- -
precision problems upstairs to answer very professional
------ For reference only -------------------------- -------------


very detailed !
------ For reference only -------------------------------------- -
I'm curious as to why the C #, floating-point arithmetic looks better than a lot of java accurate as LZ -mentioned example , in C # is an accurate one , which is what has been done deal ? java and C \ C + + , as more than 0.1 Print a few final questions will be non-zero precision , C # has been accurate in why

没有评论:

发表评论