CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 8 of 8
  1. #1
    Join Date
    Mar 2006
    Posts
    4

    Comparing very small numbers problem

    I am trying to compare two long doubles to check the difference between them is less than 1e-14. However at about 1e-9 the code stops accepts the condition. I want to taylor expansion to keep iterating until the difference between the current value and the previous value is less than 1e-14.

    The problem seems to be that long doubles in a comparison equate much earlier than they should. Does anyone know a get around?

    I have tried searching the net but have no luck yet. Any help would be useful.

    code in question
    =====================================================

    for (i=1; i<42; i++)
    {
    Approx1=1.0;
    N=1;
    Test=0;
    X=((long double)(i-1)/40.0);
    {
    Approx2 = Approx1;
    Nfact = fFactorial(N); //call factorial

    Approx1 += (pow(X, N)/(Nfact)); //approximation of e^x

    Difference = (Approx1 - Approx2);
    N++;
    }while(Difference > 1E-14);

    cout << i << "\t" << X << "\t";
    cout << Approx1 <<endl; //DEBUG


    for (j=1; j<79; j++) //put the graph points in the right place
    {
    if (Test == 1)
    ExpArray[i][j] = ' ';
    else
    {
    if ((Approx1 - 1.0)> ((long double)j*2.0/80.0)) /
    ExpArray[i][j] = ' ';
    else
    {
    ExpArray[i][j] = '*';
    Test = 1;
    }
    }

    }

  2. #2
    Join Date
    Apr 1999
    Posts
    27,449

    Re: Comparing very small numbers problem

    One big mistake you're making:

    You're supposed to be comparing the absolute value of the difference of the values, not just the difference of the values.

    Regards,

    Paul McKenzie

  3. #3
    Join Date
    Mar 2006
    Posts
    4

    Re: Comparing very small numbers problem

    Thanks but the abs isn't necessary as it always increments.

    I've solved that problem, the fFactorial was an int not a long double, so after n=13 it turned negative.

    Now I am trying to make something more robust.

    I am using stringstream to convert the long double to a string. The problem i have is that the long double converts to 1E-005 instead of 0.00001. In the form of 1.02E-005 i can't compare it with my required string (the precision).

    Any ideas?


    int fString(long double Difference){ // string comparison

    int test = 0, i;
    string compare = "0.000000000000001", val;
    stringstream s;
    s << Difference; // insert double into stream
    s >> val;
    cout << compare << "\t" << val << "\n";
    getchar();
    for (i=0; compare[i] == val[i] ; i++)
    cout << compare [i] << "\t" << val[i] << "\n";
    if (i > 6)
    test = 1;
    return test;
    }

  4. #4
    Join Date
    Apr 1999
    Posts
    27,449

    Re: Comparing very small numbers problem

    Quote Originally Posted by plainz
    Thanks but the abs isn't necessary as it always increments.
    What do you mean by "it always increments"? What is the "it"?

    Bottom line: You are comparing if two values are within a certain tolerance level, and the correct way to do that is to take the absolute value of the difference. Look at any book or article on comparison of floating point values.

    Regards,

    Paul McKenzie
    Last edited by Paul McKenzie; March 25th, 2006 at 11:45 PM.

  5. #5
    Join Date
    Apr 1999
    Posts
    27,449

    Re: Comparing very small numbers problem

    Quote Originally Posted by plainz
    I am using stringstream to convert the long double to a string. The problem i have is that the long double converts to 1E-005 instead of 0.00001. In the form of 1.02E-005 i can't compare it with my required string (the precision).
    I don't understand what you're trying to do. On a high-level, what is it that you are trying to accomplish?

    Why not just make both doubles, and compare the difference of the doubles?

    There is no guarantee that the double you give the strstream is what will be given back to you when you extract it from the strstream, just by the very nature of floating point values not being exact. So expecting exactly the same double to come out of the strstream as what you placed there is not realistic.

    Regards,

    Paul McKenzie

  6. #6
    Join Date
    Mar 2006
    Posts
    4

    Re: Comparing very small numbers problem

    Managed to solve the problems.

    I know its best to use abs but what i meant was the value will always be positive so it is really redundant in my example.

    I know with very small numbers (precision 10e-14) sometimes similar values are equated depending upon your computer and compiler. By converting the double to a string and comparing it with a string "0.00000000000000" i could check each if the characters match and return a true or false value depending if the precision had reached the required point. At least that's what i was informed was the most reliable way of comparing extreme numbers.

    As i just check for precision i don't convert back to double.

    What you say about stringstream does that mean it not a reliable way on converting long double to string?

    Thanks for help anyways.

  7. #7
    Join Date
    Mar 2006
    Posts
    4

    Re: Comparing very small numbers problem

    This is what i ended up with for the precision test:

    int fString(long double Difference, short int precision){ // string comparison to get accurate check of difference
    int test = 0, i=0;
    string compare = "0.000000000000000000", val; //will not be more than this
    stringstream s;
    s << fixed; //fixed otherwise uses scientific notation
    s.precision(15); //overdo precision
    s << Difference; // insert double into stream
    s >> val;
    // cout << endl << Difference <<endl; // debugcode
    for (i=0; compare[i] == val[i] ; i++);
    if (i > (precision)) // so precision is greater than 10e-precision
    test = 1;
    return test;
    }

  8. #8
    Join Date
    Feb 2005
    Location
    Normandy in France
    Posts
    4,590

    Re: Comparing very small numbers problem

    I tried that code:
    Code:
    #include <cmath>
    #include <iostream>
    using std::cout;
    using std::endl;
    
    long double fFactorial(int N)
    {
    long double r=1;
    while(N>0) {r *= N;--N;}
    return r;
    }
    
    int main()
    {
    int i;
    long double Approx1,Approx2,Nfact,Difference;
    long double X;
    int N;
    
    cout.precision(15);
    for (i=1; i<42; i++)
    {
    Approx1=1.0;
    N=1;
    X=(((long double)(i-1))/40.0);
    do
    {
    Approx2 = Approx1;
    Nfact = fFactorial(N); //call factorial
    
    Approx1 += (std::pow(X,N)/(Nfact)); //approximation of e^x
    
    Difference = (Approx1 - Approx2);
    N++;
    cout << Difference << '\n';
    }while(Difference > 1E-14);
    
    cout << i << "\t" << X << "\t";
    cout << Approx1 <<endl; //DEBUG
    }
    
    }
    And, it works perfectly on my computer.

    Here is the output of the last operations:
    Code:
    1
    0.5
    0.166666666666667
    0.0416666666666667
    0.00833333333333333
    0.00138888888888889
    0.000198412698412698
    2.48015873015872e-05
    2.75573192239868e-06
    2.75573192239868e-07
    2.50521083853834e-08
    2.08767569876388e-09
    1.60590438299732e-10
    1.14707455773494e-11
    7.6471641519138e-13
    4.7794667529244e-14
    2.81155307368941e-15
    41      1       2.71828182845905
    Quote Originally Posted by plainz
    By converting the double to a string and comparing it with a string "0.00000000000000" i could check each if the characters match and return a true or false value depending if the precision had reached the required point.
    You can only loose precision like that.
    "inherit to be reused by code that uses the base class, not to reuse base class code", Sutter and Alexandrescu, C++ Coding Standards.
    Club of lovers of the C++ typecasts cute syntax: Only recorded member.

    Out of memory happens! Handle it properly!
    Say no to g_new()!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured