(float / double)

Discussion in 'C++' started by abdul_n_khan@hotmail.com, Mar 4, 2006.

  1. Guest

    Hello,
    I have a basic question related to datatypes.
    I am trying to read a value using Microsoft's ADO recordset from a
    field (lets call it 'Price') with datatype decimal(19,6) => 19 =
    Precision, 6 = Scale


    1) When I read this field into float datatype. I get a value 1.9000,
    which is correct. But when I read its value in a double datatype I get
    1.8999999761581.


    2) My second question is related to multiplication.
    Should it cause any problem?

    dblPrice =1.23333;
    Amount = 91000000;
    PricedAmount= dblPrice * Amount
    PricedAmountshould have 112233030

    But i am getting 112230300 (thus I am loosing precision).

    Here is the implementation of Multiplication operator of CCurrency
    class



    CCurrency CCurrency::eek:perator*(float nOperand) const
    {
    if (!GetStatus() == valid)
    return *this;
    CCurrency curOperand;
    VarCyFromR4(nOperand,&curOperand.m_cur);
    CCurrency curResult;
    HRESULT hr = VarCyMul(*this, curOperand,&curResult.m_cur);
    if FAILED(hr)
    {
    curResult.SetStatus(invalid);
    curResult.m_cur.int64 = 0;
    }
    return curResult;
    }

    CCurrency CCurrency::eek:perator*(double nOperand) const
    {
    if (!GetStatus() == valid)
    return *this;
    CCurrency curOperand;
    VarCyFromR8(nOperand,&curOperand.m_cur);
    CCurrency curResult;
    HRESULT hr = VarCyMul(*this, curOperand,&curResult.m_cur);
    if FAILED(hr)
    {
    curResult.SetStatus(invalid);
    curResult.m_cur.int64 = 0;
    }
    return curResult;
    }
     
    , Mar 4, 2006
    #1
    1. Advertising

  2. On 4 Mar 2006 07:36:39 -0800, wrote:

    >Hello,
    >I have a basic question related to datatypes.
    >I am trying to read a value using Microsoft's ADO recordset from a
    >field (lets call it 'Price') with datatype decimal(19,6) => 19 =
    >Precision, 6 = Scale
    >
    >
    >1) When I read this field into float datatype. I get a value 1.9000,
    >which is correct. But when I read its value in a double datatype I get
    >1.8999999761581.


    DECIMAL is a fixed-point numeric type, and such numbers often cannot
    be expressed exactly as a floating-point number in a computer. For
    example, 1.5 can be stored exactly with no loss of precision because
    0.5 is equivalent to 1/2 which is 0.1 in binary notation. Similarly,
    any other number which can be expressed as the sum of various powers
    of 2 can be represented exactly. But not 1/10, for example, and not
    9/10.

    The float value *appears* to be exactly the same as the number in the
    database. In reality, the ODBC driver has rounded the value for you.
    The double has more precision, so you see the effects of the rounding
    errors between decimal and floating-point types.

    >2) My second question is related to multiplication.
    >Should it cause any problem?
    >
    >dblPrice =1.23333;
    >Amount = 91000000;
    >PricedAmount= dblPrice * Amount
    >PricedAmountshould have 112233030
    >
    >But i am getting 112230300 (thus I am loosing precision).


    Obviously.

    >Here is the implementation of Multiplication operator of CCurrency
    >class
    >
    >
    >
    >CCurrency CCurrency::eek:perator*(float nOperand) const
    >{
    > if (!GetStatus() == valid)
    > return *this;
    > CCurrency curOperand;
    > VarCyFromR4(nOperand,&curOperand.m_cur);
    > CCurrency curResult;
    > HRESULT hr = VarCyMul(*this, curOperand,&curResult.m_cur);
    > if FAILED(hr)
    > {
    > curResult.SetStatus(invalid);
    > curResult.m_cur.int64 = 0;
    > }
    > return curResult;
    >}
    >
    >CCurrency CCurrency::eek:perator*(double nOperand) const
    >{
    > if (!GetStatus() == valid)
    > return *this;
    > CCurrency curOperand;
    > VarCyFromR8(nOperand,&curOperand.m_cur);
    > CCurrency curResult;
    > HRESULT hr = VarCyMul(*this, curOperand,&curResult.m_cur);
    > if FAILED(hr)
    > {
    > curResult.SetStatus(invalid);
    > curResult.m_cur.int64 = 0;
    > }
    > return curResult;
    >}


    My suggestion would be to implement CCurrency as a decimal scaled
    integer value (i.e., use long long if you have it, else __int64) and
    not as a double. That way, you avoid the rounding problems.

    But how many digits will you need? Do any of the values in the
    database exceed INT64_MAX scaled to a precision of 6? If so, you'll
    need to either look for a third-party solution or implement one
    yourself.

    --
    Bob Hairgrove
     
    Bob Hairgrove, Mar 4, 2006
    #2
    1. Advertising

  3. wrote:
    > I have a basic question related to datatypes.
    > I am trying to read a value using Microsoft's ADO recordset from a
    > field (lets call it 'Price') with datatype decimal(19,6) => 19 =
    > Precision, 6 = Scale
    >
    >
    > 1) When I read this field into float datatype. I get a value 1.9000,
    > which is correct. But when I read its value in a double datatype I get
    > 1.8999999761581.


    Do you know how those numbers (19 and 6) relate to the significant
    digits and the range of the number? Since MS ADO "recordset" is not
    defined in C++, you have to tell us. Then together we can think why
    you see what you see.

    > 2) My second question is related to multiplication.
    > Should it cause any problem?
    >
    > dblPrice =1.23333;
    > Amount = 91000000;
    > PricedAmount= dblPrice * Amount
    > PricedAmountshould have 112233030
    >
    > But i am getting 112230300 (thus I am loosing precision).


    "Losing". Well, how are 'dblPrice' and 'Amount' declared? Hos is
    'PricedAmount' declared?

    > Here is the implementation of Multiplication operator of CCurrency
    > class
    > [..]


    How is this relevant to your questions?

    If you need an industrial-strength system for handling money, you
    should _not_ use 'float' or even 'double'. You should implement
    your own numeric representation based most likely on fixed-point
    arithmetic with something like 5 digits after the decimal point.

    Look on the web for 'fixed-point arithmetic' and you shall find.

    V
    --
    Please remove capital As from my address when replying by mail
     
    Victor Bazarov, Mar 4, 2006
    #3
  4. Guest

    Amount & PricedAmount are objects of CCurrency class (implementation is
    part of my own project).

    dblPrice is declared as double.

    Implementation of CCurrency is as follows
    ---
    class CCurrency
    {
    // Constructors
    public:
    CCurrency();
    CCurrency(CURRENCY cySrc);
    CCurrency(const CCurrency& curSrc);
    CCurrency(const _variant_t & varSrc);
    CCurrency(long nUnits, long nFractionalUnits);
    CCurrency(__int64 int64Value);
    // Attributes
    public:
    enum CCurrencyStatus
    {
    valid = 0,
    invalid = 1, // Invalid currency (overflow, div 0, etc.)
    null = 2, // Literally has no value
    };
    CURRENCY m_cur;
    CCurrencyStatus m_status;
    void SetStatus(CCurrencyStatus status);
    CCurrencyStatus GetStatus() const;
    // Operations
    public:

    const CCurrency& operator=(CURRENCY cySrc);
    const CCurrency& operator=(const CCurrency& curSrc);
    const CCurrency& operator=(const _variant_t & varSrc);

    BOOL operator==(const CCurrency& cur) const;
    BOOL operator!=(const CCurrency& cur) const;
    BOOL operator<(const CCurrency& cur) const;
    BOOL operator>(const CCurrency& cur) const;
    BOOL operator<=(const CCurrency& cur) const;
    BOOL operator>=(const CCurrency& cur) const;

    // CCurrency math
    CCurrency operator+(const CCurrency& cur) const;
    CCurrency operator-(const CCurrency& cur) const;
    const CCurrency& operator+=(const CCurrency& cur);
    const CCurrency& operator-=(const CCurrency& cur);
    CCurrency operator-() const;

    CCurrency operator*(const CCurrency& cur) const;

    CCurrency operator*(long nOperand) const;
    CCurrency operator*(float nOperand) const;
    CCurrency operator*(double nOperand) const;
    CCurrency operator/(long nOperand) const;
    CCurrency operator/(float nOperand) const;
    CCurrency operator/(double nOperand) const;

    const CCurrency& operator*=(long nOperand);
    const CCurrency& operator/=(long nOperand);
    const CCurrency& operator*=(float nOperand);
    const CCurrency& operator/=(float nOperand);
    const CCurrency& operator*=(double nOperand);
    const CCurrency& operator/=(double nOperand);

    operator CURRENCY() const;
    operator _variant_t() const;

    // CCurrency definition
    void SetCurrency(long nUnits, long nFractionalUnits);
    CCurrency Absolute();
    };
    ---


    Victor Bazarov wrote:
    > wrote:
    > > I have a basic question related to datatypes.
    > > I am trying to read a value using Microsoft's ADO recordset from a
    > > field (lets call it 'Price') with datatype decimal(19,6) => 19 =
    > > Precision, 6 = Scale
    > >
    > >
    > > 1) When I read this field into float datatype. I get a value 1.9000,
    > > which is correct. But when I read its value in a double datatype I get
    > > 1.8999999761581.

    >
    > Do you know how those numbers (19 and 6) relate to the significant
    > digits and the range of the number? Since MS ADO "recordset" is not
    > defined in C++, you have to tell us. Then together we can think why
    > you see what you see.
    >
    > > 2) My second question is related to multiplication.
    > > Should it cause any problem?
    > >
    > > dblPrice =1.23333;
    > > Amount = 91000000;
    > > PricedAmount= dblPrice * Amount
    > > PricedAmountshould have 112233030
    > >
    > > But i am getting 112230300 (thus I am loosing precision).

    >
    > "Losing". Well, how are 'dblPrice' and 'Amount' declared? Hos is
    > 'PricedAmount' declared?
    >
    > > Here is the implementation of Multiplication operator of CCurrency
    > > class
    > > [..]

    >
    > How is this relevant to your questions?
    >
    > If you need an industrial-strength system for handling money, you
    > should _not_ use 'float' or even 'double'. You should implement
    > your own numeric representation based most likely on fixed-point
    > arithmetic with something like 5 digits after the decimal point.
    >
    > Look on the web for 'fixed-point arithmetic' and you shall find.
    >
    > V
    > --
    > Please remove capital As from my address when replying by mail
     
    , Mar 5, 2006
    #4
  5. Guest

    Hello,
    I am working on a program written by someone else and facing problems
    in precisions due to usage of floating point date types. My input is
    are the values in the rows of database (MS SQL Server) where fixed
    point datatypes are used to store input as well as result e.g.
    decimal(16,6) & money.

    As the end I end up only using precision of 4 decimal instead of 6.

    dblPrice =1.23333;
    Amount = 91000000;
    PricedAmount= dblPrice * Amount
    PricedAmountshould have 112233030

    But i am getting 112230300 (thus I am loosing precision).

    dblPrice is declared as double
    PricedAmount and Amount are objects of CCurrency

    Here is the implementation of Multiplication operator of CCurrency
    class and declaration of CCurrency

    Any help to make this program more robust for more real implementation.

    I have started to consider writign a class for fixed point arithmatic
    datatype. Please let me know if it is a good start.

    thanks and best wishes

    abdul n. khan

    ---
    class CCurrency
    {
    // Constructors
    public:
    CCurrency();
    CCurrency(CURRENCY cySrc);
    CCurrency(const CCurrency& curSrc);
    CCurrency(const _variant_t & varSrc);
    CCurrency(long nUnits, long nFractionalUnits);
    CCurrency(__int64 int64Value);
    // Attributes
    public:
    enum CCurrencyStatus
    {
    valid = 0,
    invalid = 1, // Invalid currency (overflow, div 0,
    etc.)
    null = 2, // Literally has no value
    };
    CURRENCY m_cur;
    CCurrencyStatus m_status;
    void SetStatus(CCurrencyStatus status);
    CCurrencyStatus GetStatus() const;
    // Operations
    public:

    const CCurrency& operator=(CURRENCY cySrc);
    const CCurrency& operator=(const CCurrency& curSrc);
    const CCurrency& operator=(const _variant_t & varSrc);

    BOOL operator==(const CCurrency& cur) const;
    BOOL operator!=(const CCurrency& cur) const;
    BOOL operator<(const CCurrency& cur) const;
    BOOL operator>(const CCurrency& cur) const;
    BOOL operator<=(const CCurrency& cur) const;
    BOOL operator>=(const CCurrency& cur) const;

    // CCurrency math
    CCurrency operator+(const CCurrency& cur) const;
    CCurrency operator-(const CCurrency& cur) const;
    const CCurrency& operator+=(const CCurrency& cur);
    const CCurrency& operator-=(const CCurrency& cur);
    CCurrency operator-() const;

    CCurrency operator*(const CCurrency& cur) const;

    CCurrency operator*(long nOperand) const;
    CCurrency operator*(float nOperand) const;
    CCurrency operator*(double nOperand) const;
    CCurrency operator/(long nOperand) const;
    CCurrency operator/(float nOperand) const;
    CCurrency operator/(double nOperand) const;

    const CCurrency& operator*=(long nOperand);
    const CCurrency& operator/=(long nOperand);
    const CCurrency& operator*=(float nOperand);
    const CCurrency& operator/=(float nOperand);
    const CCurrency& operator*=(double nOperand);
    const CCurrency& operator/=(double nOperand);

    operator CURRENCY() const;
    operator _variant_t() const;

    // CCurrency definition
    void SetCurrency(long nUnits, long nFractionalUnits);
    CCurrency Absolute();
    };

    CCurrency CCurrency::eek:perator*(float nOperand) const
    {
    if (!GetStatus() == valid)
    return *this;
    CCurrency curOperand;
    VarCyFromR4(nOperand,&curOperand.m_cur);
    CCurrency curResult;
    HRESULT hr = VarCyMul(*this, curOperand,&curResult.m_cur);
    if FAILED(hr)
    {
    curResult.SetStatus(invalid);
    curResult.m_cur.int64 = 0;
    }
    return curResult;

    }

    CCurrency CCurrency::eek:perator*(double nOperand) const
    {
    if (!GetStatus() == valid)
    return *this;
    CCurrency curOperand;
    VarCyFromR8(nOperand,&curOperand.m_cur);
    CCurrency curResult;
    HRESULT hr = VarCyMul(*this, curOperand,&curResult.m_cur);
    if FAILED(hr)
    {
    curResult.SetStatus(invalid);
    curResult.m_cur.int64 = 0;
    }
    return curResult;
    }
     
    , Mar 6, 2006
    #5
  6. Ben Pope Guest

    wrote:
    > Hello,
    > I am working on a program written by someone else and facing problems
    > in precisions due to usage of floating point date types. My input is
    > are the values in the rows of database (MS SQL Server) where fixed
    > point datatypes are used to store input as well as result e.g.
    > decimal(16,6) & money.
    >
    > As the end I end up only using precision of 4 decimal instead of 6.


    So far two people have responded and they both, independently told you
    no to use floating point to represent currency. Dare I say, don't use
    floating point to store currency?

    > Any help to make this program more robust for more real implementation.


    Well, ignoring the responses you don't like won't solve it.

    > I have started to consider writign a class for fixed point arithmatic
    > datatype. Please let me know if it is a good start.


    That's specifically what you have been told to do. At least twice.

    Ben Pope
    --
    I'm not just a number. To many, I'm known as a string...
     
    Ben Pope, Mar 6, 2006
    #6
  7. Guest

    Hello ben
    Which data type should I use to store decimal(16,6)?
     
    , Mar 6, 2006
    #7
  8. Guest

    Hello ben
    Which data type should I use to store decimal(16,6)?
     
    , Mar 6, 2006
    #8
  9. Guest

    1) database datatype "money" is being handled by class CCurrency, which
    uses structure CURRENCY that is defined by
    typedef struct tagCY
    {
    unsigned long Lo;
    long Hi;
    } CURRENCY;
    Members
    Lo : Low-order 32 bits of the currency value.
    Hi : High-order 32 bits of the currency value.
    Remarks : The CURRENCY structure is a scaled integer representation of
    a decimal number with four digits to the right of the decimal point. A
    stored value of 327500, for example, is to be construed as representing
    a currency value of 32.7500.

    Therefore in my understanding "database datatype money" is being
    handled by fixed point datatype instead of floating point. Please
    correct me if I am wrong here.

    The only problem is handling of "database datatype decimal(16,6)". I
    know that I (or someone who originally wrote the program) shouldn't
    have used troubling floating point datatype (single precision / double
    precision).

    But what alternate solution should I be doing? In my understanding that
    is a very typical and generic problem that is taken care by many
    people. I will appreciate any help to some article or documentation or
    example will be of great help.

    Does C++ or MS Visual C++ support "decimal" datatype?
     
    , Mar 6, 2006
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Andy
    Replies:
    7
    Views:
    6,329
    Roedy Green
    May 10, 2004
  2. JKop
    Replies:
    4
    Views:
    16,573
  3. Sydex
    Replies:
    12
    Views:
    6,651
    Victor Bazarov
    Feb 17, 2005
  4. bd
    Replies:
    0
    Views:
    666
  5. Carsten Fuchs
    Replies:
    45
    Views:
    1,652
    James Kanze
    Oct 8, 2009
Loading...

Share This Page