float comparison not working

Hi!
I have a simple class item as follows:
[code]
class recipt::item
{
std::string nme;
float pr;

public:
item(std::string n, float p): nme(n), pr(p) {};
virtual ~item() {};

const std::string& name() {
return nme;
}

const float& price() {
return pr;
}

};
[/code]

It's purpose (once it grows a bit) will be to store information about items to be added to a printable recipt.

Along with this class, I have a simple test function (as I do with all my classes, even if it is ridiculously simple), as follows:

[code]
#include "./item.h"
bool test_item()
{
using std::string;
using recipt::item;

const string name = "Item Test";
item itm(name, 12.99);

cout << (itm.name() == name) << " " << (itm.price() == 12.99) << endl;
if (itm.name() == name && itm.price() == 12.99)
return true;
else
{
return false;
}
}
[/code]

The cout line is there to indicate which comparison is failing. Strangely, the itm.price() == 12.99 item is failing, and yet when I print itm.price() out, it displays as 12.99.

I'm using the g++ compiler, on a debian linux box.

Does anyone know what might cause this to fail?

Sincerely,
Jakykong (Jack Mudge)
jack_mudge@hotmail.com

Comments

  • : Hi!
    : I have a simple class item as follows:
    : [code]:
    : class recipt::item
    : {
    : std::string nme;
    : float pr;
    :
    : public:
    : item(std::string n, float p): nme(n), pr(p) {};
    : virtual ~item() {};
    :
    : const std::string& name() {
    : return nme;
    : }
    :
    : const float& price() {
    : return pr;
    : }
    :
    : };
    : [/code]:
    :
    : It's purpose (once it grows a bit) will be to store information
    : about items to be added to a printable recipt.
    :
    : Along with this class, I have a simple test function (as I do with
    : all my classes, even if it is ridiculously simple), as follows:
    :
    : [code]:
    : #include "./item.h"
    : bool test_item()
    : {
    : using std::string;
    : using recipt::item;
    :
    : const string name = "Item Test";
    : item itm(name, 12.99);
    :
    : cout << (itm.name() == name) << " " << (itm.price() == 12.99) << endl;
    : if (itm.name() == name && itm.price() == 12.99)
    : return true;
    : else
    : {
    : return false;
    : }
    : }
    : [/code]:
    :
    : The cout line is there to indicate which comparison is failing.
    : Strangely, the itm.price() == 12.99 item is failing, and yet when I
    : print itm.price() out, it displays as 12.99.
    :
    : I'm using the g++ compiler, on a debian linux box.
    :
    : Does anyone know what might cause this to fail?
    :
    : Sincerely,
    : Jakykong (Jack Mudge)
    : jack_mudge@hotmail.com

    [color=Blue]
    Try this first: compare the values using memory comparison. Just to test the theory.
    [code]
    double value1 = item.price ();
    double value2 = 12.99;
    int valuesAreEqual = (memcmp (&value1, &value2, sizeof (double)) == 0);
    [/code]
    To make it interesting (in case valuesAreEqual is 0), check these memory dumps you are comparing in debugger. Of course, if valuesAreEqual is 1, then the "==" statement should have worked. If that is the case, then I have no idea what to do next. If valuesAreEqual still 0, then read below.

    Establish the equality of float point values using deltas:
    [code]
    #define EQUAL_DOUBLE(value1, value2) ((value1 > (value2 - 0.000000000001)) && (value1 < (value2 + 0.000000000001)))

    if (EQUAL_DOUBLE (item.price (), 12.99))
    {
    // they are equal with precision of +/- 0.000000000001
    }
    [/code]
    The point of this is that when you do the calculations or conversions from one type to another - the values may lose the precision. Example: try to divide the 10 by 3. You will get the 3.333333333... (and so on). But float point registers are not endless, so they lose the tail of ".000000000000000000000[italic]33333333333[/italic]". Now, if you muliply the result with 3 again - you are not getting 10.00000, but less than that. During Float Point math it happens a lot.

    And another point, when you do something with a currency - you should avoid using the float point math. Instead you need a new type of variable (maybe even a C++ class) which encapsulates both dollars and cents:
    [code]
    typedef struct
    {
    int Dollars;
    int Cents;
    }
    CURRENCY;
    [/code]
    In this way you cannot lose even a cent from your calculations. Of course you need to write now such operations as:

    CURRENCY minus CURRENCY
    CURRENCY plus CURRENCY
    CURRENCY multiply by integer value
    get percentage from CURRENCY

    and so on... whatever needed for business.

    That is how banks doing their software. However, this CURRENCY structure can hold only about 4 billion bucks at maximum, but I am sure banks have their own programming tricks to get around that (simply using the [italic]longlong[/italic] type will fix it)
    [/color]
  • : Hi!
    : I have a simple class item as follows:
    : [code]:
    : class recipt::item
    : {
    : std::string nme;
    : float pr;
    :
    : public:
    : item(std::string n, float p): nme(n), pr(p) {};
    : virtual ~item() {};
    :
    : const std::string& name() {
    : return nme;
    : }
    :
    : const float& price() {
    : return pr;
    : }
    :
    : };
    : [/code]:
    :
    : It's purpose (once it grows a bit) will be to store information
    : about items to be added to a printable recipt.
    :
    : Along with this class, I have a simple test function (as I do with
    : all my classes, even if it is ridiculously simple), as follows:
    :
    : [code]:
    : #include "./item.h"
    : bool test_item()
    : {
    : using std::string;
    : using recipt::item;
    :
    : const string name = "Item Test";
    : item itm(name, 12.99);
    :
    : cout << (itm.name() == name) << " " << (itm.price() == 12.99) << endl;
    : if (itm.name() == name && itm.price() == 12.99)
    : return true;
    : else
    : {
    : return false;
    : }
    : }
    : [/code]:
    :
    : The cout line is there to indicate which comparison is failing.
    : Strangely, the itm.price() == 12.99 item is failing, and yet when I
    : print itm.price() out, it displays as 12.99.
    :
    : I'm using the g++ compiler, on a debian linux box.
    :
    : Does anyone know what might cause this to fail?
    :
    : Sincerely,
    : Jakykong (Jack Mudge)
    : jack_mudge@hotmail.com


    [blue]In addition to what has already been said by AsmGuru...

    [code]item itm(name, 12.99);[/code]
    This takes the [b]double[/b] value 12.99 and converts it into a [b]float[/b] which is less precise than a [b]double[/b]. This less precise [b]float[/b] value is then stored in your class called [italic]item[/italic].

    [code]if (itm.name() == name && itm.price() == 12.99)[/code]
    This is testing the [b]double[/b] value of 12.99 against the less precise (converted) [b]float[/b]
    value stored in your class and is a part of your problems.

    What you should remember: A decimal valued constant is by default taken to be a [b]double[/b] and not a [b]float[/b] when looked at by your compiler. This can all sorts of issues when trying to store these into a less precise variable and then comparing them with more precise values. You can force the compiler to treat things as a float by adding an [b]f[/b] at the end of all your values, i.e.
    [code]
    item itm(name, 12.99[b]f[/b]);
    ...
    if (itm.name() == name && itm.price() == 12.99[b]f[/b])[/code]
    This may help somewhat. However it is usually better to just use a [b]double[/b] instead of a [b]float[/b] since they are more precise or a method as suggested by AsmGuru[/blue]
  • Correct me if i'm wrong, but you both said basically the same thing: double is more precise than float, and through automatic conversion, it loses information (which, when converted back, means the values are NOT quite the same).

    So, the solution: use double instead of float.

    This solved the problem (I am now going to slap myself in the forehead).

    Thanks so much!
    Sincerely,
    Jakykong (Jack Mudge)
    jack_mudge@hotmail.com
Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Categories