0

At present I am working on piece of C++ code in which I need to read data from a database, and if database value is non-zero, then I need to apply some further logic.

But in the database there are values which are being calculated and can come out as -0.0. And this negative zero is being treated as Garbage value in C++ double variable. I have already initialized the value as 0.0 in constructor.

Sample Code:

for(Sample::List<BalanceSheet>::Iterator i((Sample::List<BalanceSheet> &) Balance.Entries()); i.HaveItem(); ++i) // This list is being populated from Database
{
    if (SomeCondition != "")
    {
        if (i->GetBalance() != 0) // This is where am getting Garbage values since GetBalance() returns -0.0
            {
             DoOperation();
            }
    }
}
Toby Speight
  • 27,591
  • 48
  • 66
  • 103
WENzER
  • 205
  • 1
  • 5
  • 15

2 Answers2

2

-0.0 is perfectly valid value for a double. The problem you are having is that you are comparing doubles for inequality.

What you should do is something like this:

i->GetBalance() > std::numeric_limits<double>::epsilon()
Toby Speight
  • 27,591
  • 48
  • 66
  • 103
Šimon Tóth
  • 35,456
  • 20
  • 106
  • 151
  • `std::numeric_limits::epsilon()` is the difference between `1.0` and the next distinctly representable value. The epsilon for a large number will be larger, the one for a small number will be smaller, but the library will only give you the epsilon for `1.0`. Using `epsilon` as a "fudge factor" in comparison *can* lead to hard-to-debug problems; make sure you know what you're doing and are positive that `epsilon` correctly applies to your algorithm. – DevSolar Nov 30 '15 at 15:48
1

First off, you should never be using == or != with floating point variables. They are essentially meaningless operations, as the limitations of floating point types mean that even seemingly innocuous values might not compare identically. It is completely possible that 2 + 2 isn't 4, at least as far as == would identify it.

The real issue here is that you are making use of the sign of a "zero" value, which as per above, might not actually be exactly zero in the first place, but more importantly, is difficult to test for using standard comparison operators. See this related question for some discussion.

The best solution for this, if you have access to C++11 or a compiler supporting it, is to use copysign as per Vlad's answer on that question. This function takes 2 parameters. The first represents the magnitude of the return value, and the second the sign. Here is an example:

#include "iostream"
#include <math.h>

using namespace std;

int main()
{
    double posZero = +0.0d;
    double negZero = -0.0d;

    if( copysign( 1, posZero ) < 0 )
    {
        cout << "posZero is negative\n";
    }
    else
    {
        cout << "posZero is positive\n";
    }

    if( copysign( 1, negZero ) < 0 )
    {
        cout << "negZero is negative\n";
    }
    else
    {
        cout << "negZero is positive\n";
    }
}

posZero is positive
negZero is negative

In this example, copysign creates a value of +/- 1, according to the sign on the second argument. The first argument for your purposes could be any non-zero value, but might as well be 1.

Alternatively, you could use signbit, which is honestly probably more direct. A version of the above using this function:

#include "iostream"
#include <math.h>

using namespace std;

int main()
{
    double posZero = +0.0d;
    double negZero = -0.0d;

    if( signbit( posZero ) )
    {
        cout << "posZero is negative\n";
    }
    else
    {
        cout << "posZero is positive\n";
    }

    if( signbit( negZero ) )
    {
        cout << "negZero is negative\n";
    }
    else
    {
        cout << "negZero is positive\n";
    }
}

With the same output.

Community
  • 1
  • 1