[PATCH] Improve (fix?) smod: now it really converts into symmetric representation...
... instead of clumsy convention inspirited by some proprietary CAS. --- doc/tutorial/ginac.texi | 2 +- ginac/numeric.cpp | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/doc/tutorial/ginac.texi b/doc/tutorial/ginac.texi index 3207a96..fe7a264 100644 --- a/doc/tutorial/ginac.texi +++ b/doc/tutorial/ginac.texi @@ -1479,7 +1479,7 @@ evaluated immediately: @tab modulus in positive representation (in the range @code{[0, abs(b)-1]} with the sign of b, or zero) @cindex @code{mod()} @item @code{smod(a, b)} -@tab modulus in symmetric representation (in the range @code{[-iquo(abs(b)-1, 2), iquo(abs(b), 2)]}) +@tab modulus in symmetric representation (in the range @code{[-iquo(abs(b), 2), iquo(abs(b), 2)]}) @cindex @code{smod()} @item @code{irem(a, b)} @tab integer remainder (has the sign of @math{a}, or is zero) diff --git a/ginac/numeric.cpp b/ginac/numeric.cpp index 91721e1..50d873a 100644 --- a/ginac/numeric.cpp +++ b/ginac/numeric.cpp @@ -2337,15 +2337,18 @@ const numeric mod(const numeric &a, const numeric &b) /** Modulus (in symmetric representation). - * Equivalent to Maple's mods. * - * @return a mod b in the range [-iquo(abs(b)-1,2), iquo(abs(b),2)]. */ -const numeric smod(const numeric &a, const numeric &b) -{ - if (a.is_integer() && b.is_integer()) { - const cln::cl_I b2 = cln::ceiling1(cln::the<cln::cl_I>(b.to_cl_N()) >> 1) - 1; - return numeric(cln::mod(cln::the<cln::cl_I>(a.to_cl_N()) + b2, - cln::the<cln::cl_I>(b.to_cl_N())) - b2); + * @return a mod b in the range [-iquo(abs(b),2), iquo(abs(b),2)]. */ +const numeric smod(const numeric &a_, const numeric &b_) +{ + if (a_.is_integer() && b_.is_integer()) { + const cln::cl_I a = cln::the<cln::cl_I>(a_.to_cl_N()); + const cln::cl_I b = cln::the<cln::cl_I>(b_.to_cl_N()); + const cln::cl_I b2 = b >> 1; + const cln::cl_I m = cln::mod(a, b); + const cln::cl_I m_b = m - b; + const cln::cl_I ret = m > b2 ? m_b : m; + return numeric(ret); } else return *_num0_p; } -- 1.5.6.5
Dear Alexei, Alexei Sheplyakov wrote:
... instead of clumsy convention inspirited by some proprietary CAS.
Ironically, your patch seems to adjust smod to the definition of that proprietary CAS. ;-)
--- doc/tutorial/ginac.texi | 2 +- ginac/numeric.cpp | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-)
diff --git a/doc/tutorial/ginac.texi b/doc/tutorial/ginac.texi index 3207a96..fe7a264 100644 --- a/doc/tutorial/ginac.texi +++ b/doc/tutorial/ginac.texi @@ -1479,7 +1479,7 @@ evaluated immediately: @tab modulus in positive representation (in the range @code{[0, abs(b)-1]} with the sign of b, or zero) @cindex @code{mod()} @item @code{smod(a, b)} -@tab modulus in symmetric representation (in the range @code{[-iquo(abs(b)-1, 2), iquo(abs(b), 2)]}) +@tab modulus in symmetric representation (in the range @code{[-iquo(abs(b), 2), iquo(abs(b), 2)]}) @cindex @code{smod()} @item @code{irem(a, b)} @tab integer remainder (has the sign of @math{a}, or is zero) diff --git a/ginac/numeric.cpp b/ginac/numeric.cpp index 91721e1..50d873a 100644 --- a/ginac/numeric.cpp +++ b/ginac/numeric.cpp @@ -2337,15 +2337,18 @@ const numeric mod(const numeric &a, const numeric &b)
/** Modulus (in symmetric representation). - * Equivalent to Maple's mods. * - * @return a mod b in the range [-iquo(abs(b)-1,2), iquo(abs(b),2)]. */ -const numeric smod(const numeric &a, const numeric &b) -{ - if (a.is_integer() && b.is_integer()) { - const cln::cl_I b2 = cln::ceiling1(cln::the<cln::cl_I>(b.to_cl_N()) >> 1) - 1; - return numeric(cln::mod(cln::the<cln::cl_I>(a.to_cl_N()) + b2, - cln::the<cln::cl_I>(b.to_cl_N())) - b2); + * @return a mod b in the range [-iquo(abs(b),2), iquo(abs(b),2)]. */ +const numeric smod(const numeric &a_, const numeric &b_) +{ + if (a_.is_integer() && b_.is_integer()) { + const cln::cl_I a = cln::the<cln::cl_I>(a_.to_cl_N()); + const cln::cl_I b = cln::the<cln::cl_I>(b_.to_cl_N()); + const cln::cl_I b2 = b >> 1; + const cln::cl_I m = cln::mod(a, b); + const cln::cl_I m_b = m - b; + const cln::cl_I ret = m > b2 ? m_b : m; + return numeric(ret); } else return *_num0_p; }
Looking at the comment and the documentation, though, it appears like your patch really adjusts it to what it was always meant to do. The interval of your function *is* [-iquo(abs(b)-1,2), iquo(abs(b),2)], and not [-iquo(abs(b),2), iquo(abs(b),2)]. This is as "symmetric" as it can get. E.g. -iquo(abs(4)-1,2) = -1, but -iquo(abs(4),2) = -2, and we have: smod(-2,4)==+2 smod(-1,4)==-1 smod(+0,4)== 0 smod(+1,4)==+1 smod(+2,4)==+2 smod(+3,4)==-1 Cheers -richy. -- Richard B. Kreckel <http://www.ginac.de/~kreckel/>
participants (2)
-
Alexei Sheplyakov
-
Richard B. Kreckel