C++ factorial, primorial
Marc Glisse
marc.glisse at inria.fr
Sun Jun 29 08:20:08 UTC 2014
On Tue, 24 Jun 2014, Torbjörn Granlund wrote:
> Marc Glisse <marc.glisse at inria.fr> writes:
>
> I am trying to make a few more functions easily available from the C++
> interface. mpz_fac_ui takes an unsigned long, so it would be natural
> to have a factorial function that takes any of {signed,unsigned}
> {char,short,int,long}. It would probably throw an out_of_range error
> for negative values. But since it does not take a gmp type as
> argument, I should not make it a free function in the global
> namespace. The easiest seems to be a static member function, so we
> would call:
>
> mpz_class::factorial(42);
>
> I don't understand what a "free function in the global namespace" might
> mean, which makes it tough for me to make a good answer.
Something like:
mpz_class factorial(unsigned long);
That would be bad because it would conflict with any other bignum library
providing:
bigint factorial(unsigned long);
where calling factorial(42) wouldn't know which one to pick.
> If we have an mpz_class that represents a small enough number, we
> would probably like to be able to use factorial on it directly without
> explicitly extracting an unsigned long. We could have
> mpz_class::factorial(z); but since there is a GMP argument, this
> versions could also be available as simply factorial(z);. Because of
> the way it would be done with templates, factorial(42) would not
> compile (it would not automatically convert 42 to mpz_class), which is
> good. However, I think we could do without this global factorial for
> now, and it can be added later if people want it.
>
> I suppose I'd need to understand the alterantives, i.e., how user code
> would look as a result of these design decisions.
Let us look at the possible ways a user could call the function (z is an
mpz_class).
1) factorial(42)
2) factorial(z)
3) mpz_class::factorial(42)
4) mpz_class::factorial(z)
5) gmpxx::factorial(42)
6) gmpxx::factorial(z)
7) z.factorial()
1 is bad, as said above. 7 is not so good because most of the time we want
to compute factorial of an int and don't want to convert it to mpz_class
first. All the others seem ok to me. Supporting both 3-4 and 5-6 seems
unnecessary. 5-6 have the advantage that a user can write:
using gmpxx::factorial;
and then use 1 and 2.
Note that factorial(mpz_class) would actually be implemented with a
template, so calling factorial(42) would not try to convert 42 to an
mpz_class.
Implementing 2-3-4 seems easy. Implementing 2-5-6 in a way that lets
"using gmpxx::factorial" work is a bit more fragile. What comes to mind
is:
namespace gmpxx { mpz_class factorial(mpz_class); }
using gmpxx::factorial;
namespace gmpxx { mpz_class factorial(unsigned long); }
(hoping that all compilers implement this import properly)
Or maybe this would be easier on bad compilers:
mpz_class factorial(mpz_class);
namespace gmpxx { using ::factorial; mpz_class factorial(unsigned long); }
--
Marc Glisse
More information about the gmp-discuss
mailing list