2

As the title says, does Boost's cpp_dec_float support modulus operations? I'm dealing with money and would like to do some modulus operations to get the number of bills and coins that I need to return. cpp_dec_float seems to be the only arbitrary precision class that supports base 10.

No_name
  • 2,732
  • 3
  • 32
  • 48
  • 1
    You should not really use floating-point types for money, even at high precision you will still have rounding errors. Instead the best way is some sort of [fixed point](http://en.wikipedia.org/wiki/Fixed-point_arithmetic) system. – Some programmer dude Aug 27 '14 at 04:41
  • Ah, I made the assumption because it was suggested under Wikipedia. Can you suggest any fixed point libraries for C++? – No_name Aug 27 '14 at 04:51
  • http://blog.haoliu.org/2014/06/07/coding-challenge-money-changer-with-c-boost-multiprecision-library/ – sehe Aug 27 '14 at 10:00
  • @JoachimPileborg in fairness, when working with money, rounding is often both expected and required. Ideally, the method and rounding points are also well specified (this is where it gets interesting). So "at high precision" doesn't really mean much, as `$100/3` usually just means `$33.33` (or `$33.3333` for intermediate results) – sehe Aug 27 '14 at 11:17

1 Answers1

2

If all you want is coin distribution, can't you just do it without modulo?

Boost multiprecision does define fmod, trunc, mod etc. whenever possible for a backend type; Here's a working demo: Live On Coliru

#include <boost/multiprecision/cpp_dec_float.hpp>
#include <boost/multiprecision/number.hpp>
#include <iostream>

using Num = boost::multiprecision::number<boost::multiprecision::cpp_dec_float<128>>;

int main()
{
    Num x("189.5307");

    for (Num denom : { 
            Num("500.00"),   Num("200.00"),   Num("100.00"),
             Num("50.00"),    Num("20.00"),    Num("10.00"),
              Num("5.00"),     Num("2.00"),     Num("1.00"),
              Num("0.50"),     Num("0.20"),     Num("0.10"),
              Num("0.05"),     Num("0.02"),     Num("0.01"),
        })
    {
        Num count = x/denom;

        if (count >= 1)
        {
            count = trunc(count);
            std::cout << count << " * " << std::right << std::setw(6) << denom.str(2, std::ios::fixed) << "\n";
            x -= denom * count;
        }
    }

    std::cout << "Remainder: " << x << "\n";
}

I explicitly selected an "invalid" input value (one with excess precision for the denominations) so you can verify it handles them. I have not bothered with the case for negative amounts, but you can figure that out :)

1 * 100.00
1 *  50.00
1 *  20.00
1 *  10.00
1 *   5.00
2 *   2.00
1 *   0.50
1 *   0.02
1 *   0.01
Remainder: 0.0007
sehe
  • 374,641
  • 47
  • 450
  • 633
  • See it **[Live On Coliru](http://coliru.stacked-crooked.com/a/3072aa29a0074332)** – sehe Aug 27 '14 at 10:52
  • You're completely right. I don't even remember why I needed modulus operations for this program. Perhaps I was thinking of something else? – No_name Aug 27 '14 at 18:38
  • fmod seems to work, but mod does not seem to be a valid function. What is your source for the api? Also, what advantages are there wrapping number on top of cpp_dec_float? – No_name Aug 27 '14 at 18:59
  • 2
    By mod I meant `operator %`. `cpp_dec_float` is a _backend_, you need to adapt it to get the higher level features (i.e. you `pow`, `trunc`, `fmod`, trig functions, expression templates, streaming operations, convenient constructions, mixed arithmetics etc. In short: all the interoperability stuff is in the _front end_.). You can also adapt as rational numbers before wrapping in the number template. – sehe Aug 27 '14 at 19:50
  • hmm, I'm getting `no match for ‘operator%’` for `x % x`. Am I doing something wrong? – No_name Aug 28 '14 at 05:54
  • 1
    I think you might have forgotten the "whenever possible" part. See e.g. http://coliru.stacked-crooked.com/a/4667bc75112750a9 – sehe Aug 28 '14 at 07:07