4

When I run this, in main() the cout prints 5.395. But the assert says it failed!! This is really mind boggling, why is this happening?

#include <iostream>
#include <cassert>

using namespace std;

const float A = 1.6;
const float C = 1.55;
const float G = 2.2;
const float T = 1.23;

char empty[18];
int arraySize;


void copyArray(char sourceArray[], char targetArray[], int size) {
    for(int i=0;i<size;i++) {
        targetArray[i] = sourceArray[i];
        }
    }



double getAvgDensity(char aminoAcid) {

char aminoUpper = toupper(aminoAcid);
aminoToArray(aminoUpper);
    double counter = 0;
    int codonTotal = arraySize / 3.0;
    if (arraySize == 0)
        return 0;
    else
    {
    for (int i = 0; i < arraySize; i++) {
        counter += charToDouble(empty[i]);
        }

    return (counter / codonTotal);
    }

}


int main()
{
    cout << getAvgDensity('A') << endl;  // prints 5.395
    assert(getAvgDensity('A')==5.395);
    return 0;
}

Edit: Thanks for all the answers, I just multiplied by 1000, converted to int, converted back to double and divided by 1000. :)

Seb
  • 1,966
  • 2
  • 17
  • 32
  • 11
    I bet you are comparig a floating point value with one that isn't precesely that... ;) – Mats Petersson Mar 13 '13 at 00:16
  • See http://stackoverflow.com/questions/1839422/strange-output-in-comparison-of-float-with-float-literal?rq=1 – John Carter Mar 13 '13 at 00:18
  • How can I fix this without changing the assert statement? – Seb Mar 13 '13 at 00:19
  • @Foxic - please don't remove essential details in the question after you have asked it. If you remove your code, you make the question useless to future readers. – Robᵩ Mar 13 '13 at 01:01

3 Answers3

10

Ah, floating point.

Say, for example, the actual return of getAvgDensity() is 5.395000000000000000000000001. It's not technically == 5.395, is it? Printing would, of course, discard all those pesky trailing decimals, but the value remains different.

When working with floats, you have to decide yourself what is an acceptable definition for "equal". Round the number manually, or compare it with <=/>= and suitable error margins.

salezica
  • 74,081
  • 25
  • 105
  • 166
1

This has already been answered, but I'll add my two cents. You may find it useful to make a function to compare doubles if you plan to do this often. The idea is to check that fabs(a-b) < epsilon where epsilon is a small value representing a tolerable amount of error.

bool is_equal( double a, double b, const double epsilon = 1e-5 )
{
    double c = a - b;
    return c < epsilon && -c < epsilon;  // or you could use fabs(c) < epsilon
}

Then it's just a case of doing this:

assert( is_equal(getAvgDensity('A'), 5.395) );
paddy
  • 60,864
  • 6
  • 61
  • 103
0

The reason is cout does not print to that high a precision by default. Try the following:

int main()
{
    std::cout.precision(25);
    cout << getAvgDensity('A') << endl;  // prints 5.395
    assert(getAvgDensity('A')==double(5.395));
    return 0;
}
user1952500
  • 6,611
  • 3
  • 24
  • 37
  • `5.395` is already a double. The cast doesn't change anything. – Pete Becker Mar 13 '13 at 01:04
  • The cast was not necessary but doesn't affect anything. If you read the comment above the code you'll see the reason. The cast not remove the assert by the way. The code modifies the precision of cout. – user1952500 Mar 13 '13 at 01:42
  • The code above does not remove the assert but helps the user understand better by printing a high-precision double. Better read the comment above the code also to understand what the code does. – user1952500 Mar 13 '13 at 01:54