// Implementation of scrt += poly, scrt -= poly, or scrt *= poly. This // implementation is safe for "in place" operation, e.g., s += s.map[i] SingleCRT& SingleCRT::Op(const ZZX &poly, void (*Fnc)(ZZ&, const ZZ&, const ZZ&, const ZZ&)) { const IndexSet& s = map.getIndexSet(); ZZX poly1, poly2; poly1 = poly; for (long i = s.first(); i <= s.last(); i = s.next(i)) { ZZ pi = to_ZZ(context.ithPrime(i)); poly2 = poly1; PolyRed(poly2,pi,/*abs=*/true); // abs=true means reduce to [0,pi-1) vec_ZZ& vp1 = map[i].rep; vec_ZZ& vp2 = poly2.rep; long len1 = vp1.length(); long len2 = vp2.length(); long maxlen = max(len1, len2); vp1.SetLength(maxlen); for (long j=len1; j < maxlen; j++) clear(vp1[j]); for (long j=0; j<len2; j++) Fnc(vp1[j], vp1[j], vp2[j], pi); map[i].normalize(); } return *this; }
// Here Fnc is either Add(ZZX,ZZX,ZZ), Sub(ZZX,ZZX,ZZ), or Mul(ZZX,ZZX,ZZ) // FIXME: this is not alias friendly SingleCRT& SingleCRT::Op(const ZZ &num, void (*Fnc)(ZZX&, const ZZX&, const ZZ&)) { const IndexSet& s = map.getIndexSet(); ZZ pi; ZZ n; ZZX poly1; for (long i = s.first(); i <= s.last(); i = s.next(i)) { conv(pi, context.ithPrime(i)); rem(n, num, pi); // n = num % pi poly1 = map[i]; Fnc(poly1,poly1,n); PolyRed(poly1,pi,/*abs=*/true); // abs=true means reduce to [0,pi-1) map[i] = poly1; } return *this; }
// Generic operators, Fnc is either AddMod or SubMod // This should have been a template, but gcc refuses to cooperate SingleCRT& SingleCRT::Op(const SingleCRT &other, void (*Fnc)(ZZ&, const ZZ&, const ZZ&, const ZZ&), bool matchIndexSets) { if (&context != &other.context) Error("SingleCRT::Op: incomopatible objects"); // Match the index sets, if needed if (matchIndexSets && !(map.getIndexSet() >= other.map.getIndexSet())) addPrimes(other.map.getIndexSet() / map.getIndexSet()); // This is expensive // INVARIANT: map.getIndexSet() >= other.map.getIndexSet()) SingleCRT tmp(context); // a rare case where you want an empty SingleCRT object const IndexMap<ZZX>* other_map = &other.map; if (map.getIndexSet() > other.map.getIndexSet()) { // Even more expensive tmp = other; tmp.addPrimes(map.getIndexSet() / other.map.getIndexSet()); other_map = &tmp.map; } const IndexSet& s = map.getIndexSet(); // add/sub polynomial, modulo the respective primes for (long i = s.first(); i <= s.last(); i = s.next(i)) { ZZ pi = to_ZZ(context.ithPrime(i)); vec_ZZ& vp1 = map[i].rep; const vec_ZZ& vp2 = (*other_map)[i].rep; long len1 = vp1.length(); long len2 = vp2.length(); long maxlen = max(len1, len2); vp1.SetLength(maxlen); for (long j=len1; j < maxlen; j++) clear(vp1[j]); for (long j=0; j<len2; j++) Fnc(vp1[j], vp1[j], vp2[j], pi); map[i].normalize(); } return *this; }
int main() { Prn(Fnc(20.2,3)); }
inline return_type operator()(const class_type& obj) const { return obj.*member_variable.*Fnc(); }