@@ -91,6 +91,14 @@ cdef class fmpz(flint_scalar):
9191 return
9292 raise TypeError (" cannot create fmpz from type %s " % type (val))
9393
94+ @property
95+ def numerator (self ):
96+ return self
97+
98+ @property
99+ def denominator (self ):
100+ return fmpz(1 )
101+
94102 # XXX: improve!
95103 def __int__ (self ):
96104 return fmpz_get_intlong(self .val)
@@ -101,6 +109,9 @@ cdef class fmpz(flint_scalar):
101109 def __index__ (self ):
102110 return fmpz_get_intlong(self .val)
103111
112+ def __float__ (self ):
113+ return float (fmpz_get_intlong(self .val))
114+
104115 def __richcmp__ (s , t , int op ):
105116 cdef bint res = 0
106117 cdef long tl
@@ -334,28 +345,171 @@ cdef class fmpz(flint_scalar):
334345 return u
335346
336347 def __pow__ (s , t , m ):
337- cdef ulong exp
338- u = NotImplemented
339- if m is not None :
340- raise NotImplementedError (" modular exponentiation" )
341- c = t
342- u = fmpz.__new__ (fmpz)
343- fmpz_pow_ui((< fmpz> u).val, (< fmpz> s).val, c)
344- return u
345-
346- def __rpow__ (s , t , m ):
347348 cdef fmpz_struct tval[1 ]
348- cdef int stype = FMPZ_UNKNOWN
349- cdef ulong exp
349+ cdef fmpz_struct mval[1 ]
350+ cdef int ttype = FMPZ_UNKNOWN
351+ cdef int mtype = FMPZ_UNKNOWN
352+ cdef int success
350353 u = NotImplemented
351- if m is not None :
352- raise NotImplementedError (" modular exponentiation" )
353354 ttype = fmpz_set_any_ref(tval, t)
354- if ttype != FMPZ_UNKNOWN:
355+ if ttype == FMPZ_UNKNOWN:
356+ return NotImplemented
357+
358+ if m is None :
359+ # fmpz_pow_fmpz throws if x is negative
360+ if fmpz_sgn(tval) == - 1 :
361+ if ttype == FMPZ_TMP: fmpz_clear(tval)
362+ raise ValueError (" negative exponent" )
363+
355364 u = fmpz.__new__ (fmpz)
356- s_ulong = fmpz_get_ui(s.val)
357- fmpz_pow_ui((< fmpz> u).val, tval, s_ulong)
365+ success = fmpz_pow_fmpz((< fmpz> u).val, (< fmpz> s).val, tval)
366+
367+ if not success:
368+ if ttype == FMPZ_TMP: fmpz_clear(tval)
369+ raise ValueError (" fmpz_pow_fmpz: exponent too large" )
370+ else :
371+ # Modular exponentiation
372+ mtype = fmpz_set_any_ref(mval, m)
373+ if mtype != FMPZ_UNKNOWN:
374+
375+ if fmpz_is_zero(mval):
376+ if ttype == FMPZ_TMP: fmpz_clear(tval)
377+ if mtype == FMPZ_TMP: fmpz_clear(mval)
378+ raise ValueError (" pow(): modulus cannot be zero" )
379+
380+ # The Flint docs say that fmpz_powm will throw if m is zero
381+ # but it also throws if m is negative. Python generally allows
382+ # e.g. pow(2, 2, -3) == (2^2) % (-3) == -2. We could implement
383+ # that here as well but it is not clear how useful it is.
384+ if fmpz_sgn(mval) == - 1 :
385+ if ttype == FMPZ_TMP: fmpz_clear(tval)
386+ if mtype == FMPZ_TMP: fmpz_clear(mval)
387+ raise ValueError (" pow(): negative modulua not supported" )
388+
389+ u = fmpz.__new__ (fmpz)
390+ fmpz_powm((< fmpz> u).val, (< fmpz> s).val, tval, mval)
391+
358392 if ttype == FMPZ_TMP: fmpz_clear(tval)
393+ if mtype == FMPZ_TMP: fmpz_clear(mval)
394+ return u
395+
396+ def __rpow__ (s , t , m ):
397+ t = any_as_fmpz(t)
398+ if t is NotImplemented :
399+ return t
400+ return t.__pow__ (s, m)
401+
402+ def __lshift__ (self , other ):
403+ if typecheck(other, fmpz):
404+ other = int (other)
405+ if typecheck(other, int ):
406+ u = fmpz.__new__ (fmpz)
407+ fmpz_mul_2exp((< fmpz> u).val, self .val, other)
408+ return u
409+ else :
410+ return NotImplemented
411+
412+ def __rlshift__ (self , other ):
413+ if typecheck(other, int ):
414+ u = fmpz.__new__ (fmpz)
415+ fmpz_mul_2exp((< fmpz> u).val, fmpz(other).val, int (self ))
416+ return u
417+ else :
418+ return NotImplemented
419+
420+ def __rshift__ (self , other ):
421+ if typecheck(other, fmpz):
422+ other = int (other)
423+ if typecheck(other, int ):
424+ u = fmpz.__new__ (fmpz)
425+ fmpz_fdiv_q_2exp((< fmpz> u).val, self .val, other)
426+ return u
427+ else :
428+ return NotImplemented
429+
430+ def __rrshift__ (self , other ):
431+ if typecheck(other, int ):
432+ u = fmpz.__new__ (fmpz)
433+ fmpz_fdiv_q_2exp((< fmpz> u).val, fmpz(other).val, int (self ))
434+ return u
435+ else :
436+ return NotImplemented
437+
438+ def __and__ (self , other ):
439+ cdef fmpz_struct tval[1 ]
440+ cdef int ttype = FMPZ_UNKNOWN
441+ ttype = fmpz_set_any_ref(tval, other)
442+ if ttype == FMPZ_UNKNOWN:
443+ return NotImplemented
444+ u = fmpz.__new__ (fmpz)
445+ fmpz_and((< fmpz> u).val, self .val, tval)
446+ if ttype == FMPZ_TMP:
447+ fmpz_clear(tval)
448+ return u
449+
450+ def __rand__ (self , other ):
451+ cdef fmpz_struct tval[1 ]
452+ cdef int ttype = FMPZ_UNKNOWN
453+ ttype = fmpz_set_any_ref(tval, other)
454+ if ttype == FMPZ_UNKNOWN:
455+ return NotImplemented
456+ u = fmpz.__new__ (fmpz)
457+ fmpz_and((< fmpz> u).val, tval, self .val)
458+ if ttype == FMPZ_TMP:
459+ fmpz_clear(tval)
460+ return u
461+
462+ def __or__ (self , other ):
463+ cdef fmpz_struct tval[1 ]
464+ cdef int ttype = FMPZ_UNKNOWN
465+ ttype = fmpz_set_any_ref(tval, other)
466+ if ttype == FMPZ_UNKNOWN:
467+ return NotImplemented
468+ u = fmpz.__new__ (fmpz)
469+ fmpz_or((< fmpz> u).val, self .val, tval)
470+ if ttype == FMPZ_TMP:
471+ fmpz_clear(tval)
472+ return u
473+
474+ def __ror__ (self , other ):
475+ cdef fmpz_struct tval[1 ]
476+ cdef int ttype = FMPZ_UNKNOWN
477+ ttype = fmpz_set_any_ref(tval, other)
478+ if ttype == FMPZ_UNKNOWN:
479+ return NotImplemented
480+ u = fmpz.__new__ (fmpz)
481+ fmpz_or((< fmpz> u).val, tval, self .val)
482+ if ttype == FMPZ_TMP:
483+ fmpz_clear(tval)
484+ return u
485+
486+ def __xor__ (self , other ):
487+ cdef fmpz_struct tval[1 ]
488+ cdef int ttype = FMPZ_UNKNOWN
489+ ttype = fmpz_set_any_ref(tval, other)
490+ if ttype == FMPZ_UNKNOWN:
491+ return NotImplemented
492+ u = fmpz.__new__ (fmpz)
493+ fmpz_xor((< fmpz> u).val, self .val, tval)
494+ if ttype == FMPZ_TMP:
495+ fmpz_clear(tval)
496+ return u
497+
498+ def __rxor__ (self , other ):
499+ cdef fmpz_struct tval[1 ]
500+ cdef int ttype = FMPZ_UNKNOWN
501+ ttype = fmpz_set_any_ref(tval, other)
502+ if ttype == FMPZ_UNKNOWN:
503+ return NotImplemented
504+ u = fmpz.__new__ (fmpz)
505+ fmpz_xor((< fmpz> u).val, tval, self .val)
506+ if ttype == FMPZ_TMP:
507+ fmpz_clear(tval)
508+ return u
509+
510+ def __invert__ (self ):
511+ u = fmpz.__new__ (fmpz)
512+ fmpz_complement((< fmpz> u).val, self .val)
359513 return u
360514
361515 def gcd (self , other ):
0 commit comments