@@ -724,6 +724,75 @@ cdef class nmod_poly(flint_poly):
724
724
)
725
725
return res
726
726
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
+
727
796
def gcd (self , other ):
728
797
"""
729
798
Returns the monic greatest common divisor of self and other.
0 commit comments