@@ -724,6 +724,75 @@ cdef class nmod_poly(flint_poly):
724724 )
725725 return res
726726
727+ def mul_low (self , other , slong n ):
728+ r """
729+ Returns the lowest ``n`` coefficients of the multiplication of ``self`` with ``other``
730+
731+ Equivalent to computing `f( x) \c dot g( x) \m od x^ n`
732+
733+ >>> f = nmod_poly( [2,3,5,7,11 ], 163)
734+ >>> g = nmod_poly( [1,2,4,8,16 ], 163)
735+ >>> f. mul_low( g, 5)
736+ 101* x^ 4 + 45* x^ 3 + 19* x^ 2 + 7* x + 2
737+ >>> f. mul_low( g, 3)
738+ 19* x^ 2 + 7* x + 2
739+ >>> f. mul_low( g, 1)
740+ 2
741+ """
742+ # Only allow multiplication with other nmod_poly
743+ if not typecheck(other, nmod_poly):
744+ raise TypeError (" other polynomial must be of type nmod_poly" )
745+
746+ if (< nmod_poly> self ).val.mod.n != (< nmod_poly> other).val.mod.n:
747+ raise ValueError (" cannot multiply nmod_polys with different moduli" )
748+
749+ cdef nmod_poly res = nmod_poly.__new__ (nmod_poly)
750+ res = nmod_poly.__new__ (nmod_poly)
751+ nmod_poly_init_preinv(res.val, self .val.mod.n, self .val.mod.ninv)
752+ nmod_poly_mullow(res.val, self .val, (< nmod_poly> other).val, n)
753+ return res
754+
755+ def pow_trunc (self , e , slong n ):
756+ r """
757+ Returns ``self`` raised to the power ``e`` modulo `x^ n`:
758+ :math:`f^ e \m od x^ n`/
759+
760+ >>> f = nmod_poly( [65, 44, 70, 33, 76, 104, 30 ], 163)
761+ >>> x = nmod_poly( [0, 1 ], 163)
762+ >>> f. pow_trunc( 2** 20, 30) == pow( f, 2** 20, x** 30)
763+ True
764+ >>> f. pow_trunc( 2** 20, 5)
765+ 132* x^ 4 + 113* x^ 3 + 36* x^ 2 + 48* x + 6
766+ >>> f. pow_trunc( 5** 25, 5)
767+ 147* x^ 4 + 98* x^ 3 + 95* x^ 2 + 33* x + 126
768+ """
769+ if e < 0 :
770+ raise ValueError (" Exponent must be non-negative" )
771+
772+ cdef nmod_poly res, tmp
773+ cdef slong e_c
774+
775+ try :
776+ e_c = e
777+ except OverflowError :
778+ # Exponent does not fit slong
779+ res = nmod_poly.__new__ (nmod_poly)
780+ tmp = nmod_poly.__new__ (nmod_poly)
781+ nmod_poly_init_preinv(res.val, self .val.mod.n, self .val.mod.ninv)
782+ nmod_poly_init_preinv(tmp.val, self .val.mod.n, self .val.mod.ninv)
783+ ebytes = e.to_bytes((e.bit_length() + 15 ) // 16 * 2 , " big" )
784+ nmod_poly_pow_trunc(res.val, self .val, ebytes[0 ] * 256 + ebytes[1 ], n)
785+ for i in range (2 , len (ebytes), 2 ):
786+ nmod_poly_pow_trunc(res.val, res.val, 1 << 16 , n)
787+ nmod_poly_pow_trunc(tmp.val, self .val, ebytes[i] * 256 + ebytes[i+ 1 ], n)
788+ nmod_poly_mullow(res.val, res.val, tmp.val, n)
789+ return res
790+
791+ res = nmod_poly.__new__ (nmod_poly)
792+ nmod_poly_init_preinv(res.val, self .val.mod.n, self .val.mod.ninv)
793+ nmod_poly_pow_trunc(res.val, self .val, e_c, n)
794+ return res
795+
727796 def gcd (self , other ):
728797 """
729798 Returns the monic greatest common divisor of self and other.
0 commit comments