Fixed precision floating point and locale facets

Discussion in 'C++' started by Roger Leigh, Nov 5, 2003.

  1. Roger Leigh

    Roger Leigh Guest

    Hello,

    I'm writing a fixed-precision floating point class, based on the ideas
    in the example fixed_pt class in the "Practical C++ Programming" book
    by Steve Oualline (O' Reilly). This uses a long int to store the
    value, and the precision (number of decimal points) is variable (it's
    a templated class):

    template <size_t _decimal_places = 4>
    class FixedFloat {
    private:
    /// The integer value.
    long int m_value;
    [...]
    };

    The value is set from a string (FixedFloat<2> ff = "12.43";), or via
    overloaded istream/ostream extraction and insertion operators (<< and
    >>) which are templated friend functions (implicit conversion to/from

    double is not allowed due to precision loss.). The conversion between
    long int and string forms is done in the latter functions.

    To output a number, I was manually splitting up the number into whole
    and fractional parts and processing them separately, using '.' as the
    decimal point symbol. However, I've just discovered the existence of
    std::locale::numeric and std::locale::monetary locale facets, and the
    num_put() and num_get() methods. Ideally, I'd like to use these
    functions for the the conversions (FixedFloat -> std::string).
    However, their support for the standard numeric types (int, long,
    float, double) is hard-coded into the class. I can't risk conversion
    to a supported type such as double, due to loss of precision (0.60
    would becomes 0.59 on my i686-pc-linux-gnu arch), and they will be
    used to process financial data!

    Is it possible to extend these to support my FixedFloat class?

    Is it reasonable to derive from std::num_put in this case? I had a
    look into the GNU libstdc++ headers to see if it was possible, but
    they were hideously complex, and I'm not keen on using the internals
    such as num_put<>::do_put and __convert_from_v(), since these are
    presumably non-portable.

    Lastly, are there any standard classes that do this sort of thing?


    Many thanks!
    Roger

    --
    Roger Leigh

    Printing on GNU/Linux? http://gimp-print.sourceforge.net/
    GPG Public Key: 0x25BFB848. Please sign and encrypt your mail.
     
    Roger Leigh, Nov 5, 2003
    #1
    1. Advertising

  2. Roger Leigh

    P.J. Plauger Guest

    "Roger Leigh" <${roger}@invalid.whinlatter.uklinux.net.invalid> wrote in message
    news:...

    > To output a number, I was manually splitting up the number into whole
    > and fractional parts and processing them separately, using '.' as the
    > decimal point symbol. However, I've just discovered the existence of
    > std::locale::numeric and std::locale::monetary locale facets, and the
    > num_put() and num_get() methods. Ideally, I'd like to use these
    > functions for the the conversions (FixedFloat -> std::string).
    > However, their support for the standard numeric types (int, long,
    > float, double) is hard-coded into the class. I can't risk conversion
    > to a supported type such as double, due to loss of precision (0.60
    > would becomes 0.59 on my i686-pc-linux-gnu arch), and they will be
    > used to process financial data!
    >
    > Is it possible to extend these to support my FixedFloat class?


    It's possible, but probably not a rewarding exercise.

    > Is it reasonable to derive from std::num_put in this case? I had a
    > look into the GNU libstdc++ headers to see if it was possible, but
    > they were hideously complex, and I'm not keen on using the internals
    > such as num_put<>::do_put and __convert_from_v(), since these are
    > presumably non-portable.


    The do_put part is portable, the other isn't. But you're right to
    observe that they're hideously complex.

    > Lastly, are there any standard classes that do this sort of thing?


    You can pervert money_put and moneypunct to output a digit sequence
    stored in a string, with a specified number of decimal places, commas
    between thousands groups, etc.

    P.J. Plauger
    Dinkumware, Ltd.
    http://www.dinkumware.com
     
    P.J. Plauger, Nov 6, 2003
    #2
    1. Advertising

  3. Roger Leigh

    Roger Leigh Guest

    "P.J. Plauger" <> writes:

    > "Roger Leigh" <${roger}@invalid.whinlatter.uklinux.net.invalid> wrote in message
    > news:...
    >
    >> To output a number, I was manually splitting up the number into whole
    >> and fractional parts and processing them separately, using '.' as the
    >> decimal point symbol. However, I've just discovered the existence of
    >> std::locale::numeric and std::locale::monetary locale facets, and the
    >> num_put() and num_get() methods. Ideally, I'd like to use these
    >> functions for the the conversions (FixedFloat -> std::string).
    >> However, their support for the standard numeric types (int, long,
    >> float, double) is hard-coded into the class. I can't risk conversion
    >> to a supported type such as double, due to loss of precision (0.60
    >> would becomes 0.59 on my i686-pc-linux-gnu arch), and they will be
    >> used to process financial data!
    >>
    >> Is it possible to extend these to support my FixedFloat class?

    >
    > It's possible, but probably not a rewarding exercise.


    If I'm correct here, I would have to add my own custom locale facet(s)
    to allow this, but I'd need to do this manually for each locale I want
    to use, which would be a pain.

    [do_put() and __convert_from_v()]
    > The do_put part is portable, the other isn't. But you're right to
    > observe that they're hideously complex.


    OK.

    >> Lastly, are there any standard classes that do this sort of thing?

    >
    > You can pervert money_put and moneypunct to output a digit sequence
    > stored in a string, with a specified number of decimal places, commas
    > between thousands groups, etc.


    This looks like what I'll do. I'll derive a "Money" class from
    FixedFloat and do that in there, overriding the standard ostream<< and
    istream>> operators.

    I've attached a copy of the working class, and a small driver program
    to show it in action (sorry it's so long). I have a few questions
    about this:

    1. Is the header file OK style-wise? Is there anything wrong that I
    should not be doing?

    2. I've noticed that the modulus (operator%) member and friend
    functions can be out by a small factor e.g. 0.0001 in a 4
    d.p. precision class. With fixed-point arithmetic, should I be
    doing anything to correct this? Is it actually incorrect? For
    some reason, I couldn't get the "real" % operator to work, so had
    to resort to the hack that actually gets used (subtracting the
    result of division and subsequent multiplication from the original
    value).

    3. Looking at the compiled binary, the FixedFloat symbols have weak,
    rather than vague linkage. I thought that /all/ templated class
    methods and functions would be vague. This is with GCC 3.3.2, GNU
    ld 2.14.90.0.6 and binutils 2.14.90.0.6-5 on i686-pc-linux-gnu
    using ELF binary format (this is probably OT).

    4. In the stream output and extraction friend classes, is the use of
    locales correct? I've not used locales (in C++) before, and I've
    done this using the Josuttis Standard Library book.


    Many thanks for your time,
    Roger


    ----begin main.cc----
    #include <iostream>

    #include "fixedfloat.h"

    int main()
    {
    std::locale::global(std::locale(""));
    std::cout.imbue(std::locale());

    FixedFloat<4> f1("4.1246");
    FixedFloat<4> f2("2.3443");

    std::cout << f1 << std::endl;
    std::cout << f2 << std::endl;

    FixedFloat<4> n(f1);
    FixedFloat<4> o;
    o = f2;

    std::cout << n << std::endl;
    std::cout << o << std::endl;

    std::cout << "Signedness\n";
    std::cout << +f1 << std::endl;
    std::cout << -f1 << std::endl;

    std::cout << "Binary arithmetic\n";
    std::cout << f1 << "-" << f2 << "=" << f1-f2 << "\n";
    std::cout << f1 << "+" << f2 << "=" << f1+f2 << "\n";
    std::cout << f1 << "*" << f2 << "=" << f1*f2 << "\n";
    std::cout << f1 << "/" << f2 << "=" << f1/f2 << "\n";
    std::cout << f1 << "%" << f2 << "=" << f1%f2 << "\n";
    std::cout << -f1 << "/" << f2 << "=" << (-f1)/f2 << "\n";
    std::cout << -f1 << "%" << f2 << "=" << (-f1)%f2 << "\n";

    std::cout << "Logic\n";
    std::cout << f1 << "==" << f1 << "=" << (f1==f1) << "\n";
    std::cout << f1 << "==" << f2 << "=" << (f1==f2) << "\n";
    std::cout << f1 << "!=" << f1 << "=" << (f1!=f1) << "\n";
    std::cout << f1 << "!=" << f2 << "=" << (f1!=f2) << "\n";

    std::cout << "Unary arithmetic\n";
    FixedFloat<4> f3 = f1;
    f3 += FixedFloat<4>("2.3430");
    std::cout << f1 << "+=2.3430" << "=" << f3 << "\n";

    f3 = f1;
    f3 -= FixedFloat<4>("2.3430");
    std::cout << f1 << "-=2.3430" << "=" << f3 << "\n";

    f3 = f1;
    f3 *= FixedFloat<4>("2.3430");
    std::cout << f1 << "*=2.3430" << "=" << f3 << "\n";

    f3 = f1;
    f3 /= FixedFloat<4>("2.3430");
    std::cout << f1 << "/=2.3430" << "=" << f3 << "\n";

    f3 = f1;
    f3 %= FixedFloat<4>("2.3430");
    std::cout << f1 << "%=2.3430" << "=" << f3 << "\n";

    f3 = f1;
    ++f3;
    std::cout << "++" << f1 << "=" << f3 << "\n";

    f3 = f1;
    std::cout << f1 << "++" << "=" << f3++ << " (before)\n";
    std::cout << f1 << "++" << "=" << f3 << " (after)\n";

    f3 = f1;
    --f3;
    std::cout << "--" << f1 << "=" << f3 << "\n";

    f3 = f1;
    std::cout << f1 << "--" << "=" << f3-- << " (before)\n";
    std::cout << f1 << "--" << "=" << f3 << " (after)\n";

    return 1;
    }
    ----end main.cc----

    ----begin fixedfloat.h----
    // fixed floating point class -*- C++ -*-
    // $Id: template.cc,v 1.1 2003/09/14 21:56:55 roger Exp $
    //
    // Copyright (C) 2003 Roger Leigh.
    //
    // Authors: Roger Leigh <>

    #include <iomanip>
    #include <istream>
    #include <locale>
    #include <ostream>
    #include <sstream>

    /**
    * A class to represent fixed floating point numbers with high
    * accuracy.
    * The float and double data types to not offer enough accuracy when
    * dealing with some types of data, for example currency values, since
    * they cannot garuantee that a particular value is representable in
    * their floating-point binary format. This class will garuantee
    * accuracy, with the restriction that there is a fixed number of
    * decimal places after the decimal point. Internally, the value is
    * held as a long integer.
    *
    * Conversion to and from the double data type is not implicit--this
    * must be done using the methods provided. However, conversion to
    * and from std::string is possible.
    */
    template <size_t _decimal_places = 2>
    class FixedFloat {
    public:
    /// The type used internally to hold fixed floating point values.
    typedef long int value_type;

    private:
    /// The integer value.
    value_type m_value;
    /// The correction factor.
    value_type m_correction;

    /**
    * Compute the correction factor.
    * The correction value is used to correct multiplication and
    * division of fixed point numbers.
    */
    void compute_correction()
    {
    m_correction = 1;
    for (int i = 0; i < _decimal_places; ++i)
    m_correction *= 10;
    }

    /**
    * The constructor.
    * The initial value is set to the value provided.
    * @param value the initial value.
    */
    FixedFloat(value_type value):
    m_value(value)
    {
    compute_correction();
    }

    public:
    /**
    * The constructor.
    * The initial value is set to 0.
    */
    FixedFloat():
    m_value(0)
    {
    compute_correction();
    }

    /**
    * The constructor.
    * The initial value is set to the value provided. If there are too
    * many numbers after the decimal place, they will be rounded to the
    * nearest representable value (0 to 4 are rounded down, 5 to 9 are
    * rounded up.
    * @param value the initial value.
    */
    FixedFloat(const std::string& value)
    {
    compute_correction();

    std::istringstream input(value);
    input >> *this;
    }

    /**
    * The copy constructor.
    */
    FixedFloat(const FixedFloat& original):
    m_value(original.m_value),
    m_correction(original.m_correction)
    {}

    /// The destructor.
    ~FixedFloat()
    {}


    FixedFloat& operator = (const FixedFloat& rhs)
    {
    m_value = rhs.m_value;
    return *this;
    }

    FixedFloat& operator += (const FixedFloat& rhs)
    {
    m_value += rhs.m_value;
    return *this;
    }

    FixedFloat& operator -= (const FixedFloat& rhs)
    {
    m_value -= rhs.m_value;
    return *this;
    }

    FixedFloat& operator *= (const FixedFloat& rhs)
    {
    m_value *= rhs.m_value;
    m_value /= m_correction;
    return *this;
    }

    FixedFloat& operator /= (const FixedFloat& rhs)
    {
    m_value *= m_correction;
    m_value /= rhs.m_value;
    return *this;
    }

    FixedFloat& operator %= (const FixedFloat& rhs)
    {
    *this = (*this - ((*this / rhs) * rhs));
    return *this;
    }

    FixedFloat& operator ++ ()
    {
    m_value += m_correction;
    return *this;
    }

    FixedFloat operator ++ (int)
    {
    FixedFloat ret(*this);
    m_value += m_correction;
    return ret;
    }

    FixedFloat& operator -- ()
    {
    m_value -= m_correction;
    return *this;
    }

    FixedFloat operator -- (int)
    {
    FixedFloat ret(*this);
    m_value -= m_correction;
    return ret;
    }

    friend FixedFloat<_decimal_places> operator +<> (const FixedFloat<_decimal_places>& lhs,
    const FixedFloat<_decimal_places>& rhs);

    friend FixedFloat<_decimal_places> operator -<> (const FixedFloat<_decimal_places>& lhs,
    const FixedFloat<_decimal_places>& rhs);

    friend FixedFloat<_decimal_places> operator *<> (const FixedFloat<_decimal_places>& lhs,
    const FixedFloat<_decimal_places>& rhs);

    friend FixedFloat<_decimal_places> operator /<> (const FixedFloat<_decimal_places>& lhs,
    const FixedFloat<_decimal_places>& rhs);

    friend FixedFloat<_decimal_places> operator %<> (const FixedFloat<_decimal_places>& lhs,
    const FixedFloat<_decimal_places>& rhs);

    friend bool operator ==<> (const FixedFloat<_decimal_places>& lhs,
    const FixedFloat<_decimal_places>& rhs);

    friend bool operator !=<> (const FixedFloat<_decimal_places>& lhs,
    const FixedFloat<_decimal_places>& rhs);

    friend FixedFloat<_decimal_places> operator -<> (const FixedFloat<_decimal_places>& rhs);

    friend FixedFloat<_decimal_places> operator +<> (const FixedFloat<_decimal_places>& rhs);

    friend std::eek:stream& operator <<<> (std::eek:stream& output_stream,
    const FixedFloat<_decimal_places>& rhs);

    friend std::istream& operator >><> (std::istream& input_stream,
    FixedFloat<_decimal_places>& rhs);

    }; // class FixedFloat<>


    // Friend functions.

    template <size_t _decimal_places>
    inline FixedFloat<_decimal_places> operator + (const FixedFloat<_decimal_places>& lhs,
    const FixedFloat<_decimal_places>& rhs)
    {
    return FixedFloat<_decimal_places>(lhs.m_value + rhs.m_value);
    }

    template <size_t _decimal_places>
    inline FixedFloat<_decimal_places> operator - (const FixedFloat<_decimal_places>& lhs,
    const FixedFloat<_decimal_places>& rhs)
    {
    return FixedFloat<_decimal_places>(lhs.m_value - rhs.m_value);
    }

    template <size_t _decimal_places>
    inline FixedFloat<_decimal_places> operator * (const FixedFloat<_decimal_places>& lhs,
    const FixedFloat<_decimal_places>& rhs)
    {
    return FixedFloat<_decimal_places>((lhs.m_value * rhs.m_value) / lhs.m_correction);
    }

    template <size_t _decimal_places>
    inline FixedFloat<_decimal_places> operator / (const FixedFloat<_decimal_places>& lhs,
    const FixedFloat<_decimal_places>& rhs)
    {
    return FixedFloat<_decimal_places>((lhs.m_value * lhs.m_correction) / rhs.m_value);
    }

    template <size_t _decimal_places>
    inline FixedFloat<_decimal_places> operator % (const FixedFloat<_decimal_places>& lhs,
    const FixedFloat<_decimal_places>& rhs)
    {
    return FixedFloat<_decimal_places>(lhs - ((lhs / rhs) * rhs));
    }

    template <size_t _decimal_places>
    inline bool operator == (const FixedFloat<_decimal_places>& lhs,
    const FixedFloat<_decimal_places>& rhs)
    {
    return lhs.m_value == rhs.m_value;
    }

    template <size_t _decimal_places>
    inline bool operator != (const FixedFloat<_decimal_places>& lhs,
    const FixedFloat<_decimal_places>& rhs)
    {
    return lhs.m_value != rhs.m_value;
    }

    template <size_t _decimal_places>
    inline FixedFloat<_decimal_places> operator - (const FixedFloat<_decimal_places>& rhs)
    {
    return FixedFloat<_decimal_places>(-rhs.m_value);
    }

    template <size_t _decimal_places>
    inline FixedFloat<_decimal_places> operator + (const FixedFloat<_decimal_places>& rhs)
    {
    return FixedFloat<_decimal_places>(rhs.m_value);
    }

    template <size_t _decimal_places>
    inline std::eek:stream& operator << (std::eek:stream& output_stream,
    const FixedFloat<_decimal_places>& rhs)
    {
    bool negative = false;
    if (rhs.m_value < 0)
    negative = true;

    typename FixedFloat<_decimal_places>::value_type whole_part
    = rhs.m_value / rhs.m_correction;
    typename FixedFloat<_decimal_places>::value_type fractional_part
    = rhs.m_value - (whole_part * rhs.m_correction);

    if (whole_part < 0) // turn into a positive number
    whole_part = -whole_part;
    if (fractional_part < 0) // turn into a positive number
    fractional_part = -fractional_part;

    std::eek:stringstream s;
    s.copyfmt(output_stream);
    s.width(0);

    if (negative == true)
    s << '-'; // output sign, if needed
    s << whole_part; // output the whole part
    if (_decimal_places > 0) // output the fractional part, including decimal point
    {
    std::eek:stringstream fractional_string;
    fractional_string.imbue(std::locale::classic()); // "plain" numbers
    fractional_string << fractional_part;

    s << std::use_facet<std::numpunct<char> >(s.getloc()).decimal_point()
    << std::setw(_decimal_places) << std::setfill('0')
    << fractional_string.str();
    }
    output_stream << s.str();

    return output_stream;
    }

    template <size_t _decimal_places>
    inline std::istream& operator >> (std::istream& input_stream,
    FixedFloat<_decimal_places>& rhs)
    {
    bool negative = false;
    typename FixedFloat<_decimal_places>::value_type whole_part = 0;
    char decimal_point;
    typename FixedFloat<_decimal_places>::value_type fractional_part = 0;

    std::istream::sentry stream_sentry(input_stream, true);

    if (stream_sentry)
    {
    // Get the whole part of the number
    if (input_stream.bad())
    return input_stream;

    // Check signedness (would be lost if value is < 1, since -0 == 0)
    if (input_stream.peek() == '+')
    negative = false;
    else if (input_stream.peek() == '-')
    negative = true;

    input_stream >> whole_part;
    whole_part *= rhs.m_correction;
    if (whole_part < 0) // turn into a positive number
    whole_part = -whole_part;
    if (_decimal_places > 0)
    {
    // Get the decimal point.
    if (input_stream.bad())
    return input_stream;

    input_stream >> decimal_point;
    // Check that the decimal point was the correct type for this locale
    if (decimal_point != std::use_facet<std::numpunct<char> >(input_stream.getloc()).decimal_point())
    {
    rhs.m_value = 0;
    input_stream.setstate(std::ios::failbit);
    }

    // Get the fractional part of the number
    fractional_part = 0;
    for (size_t i = _decimal_places; i > 0; --i)
    {
    if (input_stream.bad())
    return input_stream;

    char decimal_char = '0';
    input_stream >> decimal_char;
    if (decimal_char < '0' || decimal_char > '9')
    {
    rhs.m_value = 0;
    input_stream.setstate(std::ios::failbit);
    return input_stream;
    }
    size_t decimal_number = decimal_char - '0';

    size_t multiply_factor = 1;
    for (int j = 1; j < i; ++j)
    multiply_factor *= 10;

    fractional_part += (decimal_number * multiply_factor);
    }
    }
    if (negative == false)
    rhs.m_value = whole_part + fractional_part;
    else
    rhs.m_value = - (whole_part + fractional_part);
    }
    else
    input_stream.setstate(std::ios::failbit);

    return input_stream;
    }
    ----end fixedfloat.h----

    --
    Roger Leigh

    Printing on GNU/Linux? http://gimp-print.sourceforge.net/
    GPG Public Key: 0x25BFB848. Please sign and encrypt your mail.
     
    Roger Leigh, Nov 9, 2003
    #3
  4. Roger Leigh

    P.J. Plauger Guest

    "Roger Leigh" <${roger}@invalid.whinlatter.uklinux.net.invalid> wrote in
    message news:...

    > > You can pervert money_put and moneypunct to output a digit sequence
    > > stored in a string, with a specified number of decimal places, commas
    > > between thousands groups, etc.

    >
    > This looks like what I'll do. I'll derive a "Money" class from
    > FixedFloat and do that in there, overriding the standard ostream<< and
    > istream>> operators.
    >
    > I've attached a copy of the working class, and a small driver program
    > to show it in action (sorry it's so long). I have a few questions
    > about this:
    >
    > 1. Is the header file OK style-wise? Is there anything wrong that I
    > should not be doing?


    Sorry, I don't have time to critique what you've done in detail.
    Instead I supply below a sample use of money_put and moneypunct
    I published in The C/C++ Users Journal (April 1998), for comparative
    anatomy studies.

    > 2. I've noticed that the modulus (operator%) member and friend
    > functions can be out by a small factor e.g. 0.0001 in a 4
    > d.p. precision class. With fixed-point arithmetic, should I be
    > doing anything to correct this? Is it actually incorrect? For
    > some reason, I couldn't get the "real" % operator to work, so had
    > to resort to the hack that actually gets used (subtracting the
    > result of division and subsequent multiplication from the original
    > value).


    Not such a hack, since it's built on the basic definition. It's very
    hard to avoid 1 or even 2 ulp errors with this sort of math. That's
    why people are reconsidering decimal floating point these days.

    > 3. Looking at the compiled binary, the FixedFloat symbols have weak,
    > rather than vague linkage. I thought that /all/ templated class
    > methods and functions would be vague. This is with GCC 3.3.2, GNU
    > ld 2.14.90.0.6 and binutils 2.14.90.0.6-5 on i686-pc-linux-gnu
    > using ELF binary format (this is probably OT).


    I don't know anything about these forms of linkage. But I think
    "vague linkage" is a wonderfully surreal term, FWIW.

    > 4. In the stream output and extraction friend classes, is the use of
    > locales correct? I've not used locales (in C++) before, and I've
    > done this using the Josuttis Standard Library book.


    If it works... The example below uses our magic locale macros to
    deal with VC++ V6.0 compiler limitations.

    P.J. Plauger
    Dinkumware, Ltd.
    http://www.dinkumware.com


    --------------

    #include <iomanip>
    #include <iostream>
    #include <locale>
    using namespace std;

    // MONETARY TYPES
    typedef long double MoneyVal;

    class Money {
    public:
    Money(MoneyVal v)
    : value(v) {}
    operator MoneyVal() const
    {return (value); }
    private:
    MoneyVal value;
    };

    // Money INSERTER
    template<class _E, class _Tr> inline
    basic_ostream<_E, _Tr>& operator<<(
    basic_ostream<_E, _Tr>& _O, Money _Y)
    {typedef ostreambuf_iterator<_E, _Tr> _Iter;
    typedef money_put<_E, _Iter> _Mput;

    ios_base::iostate _St = ios_base::goodbit;
    const typename basic_ostream<_E, _Tr>::sentry _Ok(_O);
    if (_Ok)
    {try
    {const _Mput& _Fac =
    _USEFAC(_O.getloc(), _Mput);
    if (_Fac.put(_Iter(_O.rdbuf()),
    (_O.flags() & ios_base::showpos) != 0,
    _O, _O.fill(), _Y).failed())
    _St |= ios_base::badbit; }
    catch (...)
    {_O.setstate(ios_base::badbit, true); }}
    _O.setstate(_St);
    return (_O); }

    // moneypunct FOR USA LOCALE
    money_base::pattern mon_fmt = {
    money_base::symbol, money_base::space,
    money_base::sign, money_base::value};

    class Mymoneypunct
    : public moneypunct<char, false> {
    protected:
    virtual char do_decimal_point() const
    {return ('.'); }
    virtual char do_thousands_sep() const
    {return (','); }
    virtual string do_grouping() const
    {return (string("\3")); }
    virtual string do_curr_symbol() const
    {return (string("$")); }
    virtual string do_positive_sign() const
    {return (string("")); }
    virtual string do_negative_sign() const
    {return (string("-")); }
    virtual int do_frac_digits() const
    {return (2); }
    virtual pattern do_pos_format() const
    {return (mon_fmt); }
    virtual pattern do_neg_format() const
    {return (mon_fmt); }
    };

    int main()
    {locale loc = _ADDFAC(locale::classic(), new Mymoneypunct);
    cout.imbue(loc);

    cout << showbase << setw(20) << internal << setfill('*')
    << Money(123456789.0) << endl;
    return (0); }
     
    P.J. Plauger, Nov 11, 2003
    #4
  5. Roger Leigh

    Roger Leigh Guest

    "P.J. Plauger" <> writes:

    > "Roger Leigh" <${roger}@invalid.whinlatter.uklinux.net.invalid> wrote in
    > message news:...
    >> 2. I've noticed that the modulus (operator%) member and friend
    >> functions can be out by a small factor e.g. 0.0001 in a 4
    >> d.p. precision class. With fixed-point arithmetic, should I be
    >> doing anything to correct this? Is it actually incorrect? For
    >> some reason, I couldn't get the "real" % operator to work, so had
    >> to resort to the hack that actually gets used (subtracting the
    >> result of division and subsequent multiplication from the original
    >> value).

    >
    > Not such a hack, since it's built on the basic definition. It's very
    > hard to avoid 1 or even 2 ulp errors with this sort of math. That's
    > why people are reconsidering decimal floating point these days.


    I noticed your post in the thread about this in comp.lang.c.moderated.
    This looks quite exciting, and I look forward to using this in the
    future, when it's implemented. Are there any C++ classes implementing
    this yet?

    I've got hold of the specs from the IBM Hursley site, and also some
    docs about BCD arithmetic. If it's not too hairy, I might be able to
    knock out a C++ class for this myself, but I'm not a mathematician and
    worry about the subtleties I might get wrong when dealing with
    financial stuff.

    For the time being, I've been looking for other classes and libraries
    out there. GNU MP (libgmp) looks like a decent choice, since it can
    do arbitrary-precision computation, and it has a C++ binding. I
    wouldn't have to worry about overflow or underflow if I used this.
    However, the values still have to be stored in a fixed-precision
    backend database (PostgreSQL numeric type), so having a
    fixed-precision class to directly represent the database types would
    be highly advantageous.

    >> 3. Looking at the compiled binary, the FixedFloat symbols have weak,
    >> rather than vague linkage. I thought that /all/ templated class
    >> methods and functions would be vague. This is with GCC 3.3.2, GNU
    >> ld 2.14.90.0.6 and binutils 2.14.90.0.6-5 on i686-pc-linux-gnu
    >> using ELF binary format (this is probably OT).

    >
    > I don't know anything about these forms of linkage. But I think
    > "vague linkage" is a wonderfully surreal term, FWIW.


    :)

    With weak linkage, if the same symbol is present in multiple
    translation units, only one will be resolved by the runtime linker.
    In contrast, vague linkage means that additional copies are thrown
    away by the linker at link time, e.g. multiple template instantiations
    emitted for every translation unit (I believe this is called COMDAT on
    some platforms). I expected the latter behaviour, but didn't get it
    with my own templates (although I see it for all the Standard Library
    ones, such as basic_ofstream<> et. al.). I'll have to investigate
    this one further.

    >> 4. In the stream output and extraction friend classes, is the use of
    >> locales correct? I've not used locales (in C++) before, and I've
    >> done this using the Josuttis Standard Library book.

    >
    > If it works... The example below uses our magic locale macros to
    > deal with VC++ V6.0 compiler limitations.


    Thanks, that was quite informative. I'll be using GCC and GNU
    libstdc++5 on all our target platforms, including Windows, so I won't
    have to deal with VC++, at least initially. It would merit further
    investigation if it provided a POSIX/SUSv3 layer like Cygwin or MinGW.
    I require the Gtkmm and PostgreSQL client libraries for my current
    project, though.


    --
    Roger Leigh

    Printing on GNU/Linux? http://gimp-print.sourceforge.net/
    GPG Public Key: 0x25BFB848. Please sign and encrypt your mail.
     
    Roger Leigh, Nov 12, 2003
    #5
    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. H aka N
    Replies:
    15
    Views:
    15,825
    Ben Jones
    Mar 2, 2006
  2. Motaz Saad
    Replies:
    7
    Views:
    6,553
  3. Replies:
    4
    Views:
    1,335
    Default User
    Feb 22, 2006
  4. Hybr1dz
    Replies:
    1
    Views:
    495
    JohnDuq
    Apr 17, 2009
  5. Saraswati lakki
    Replies:
    0
    Views:
    1,416
    Saraswati lakki
    Jan 6, 2012
Loading...

Share This Page