diff --git a/.gitignore b/.gitignore index 075ec3ce..392b7644 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ MANIFEST *.DS_Store .venv .hypothesis +venv/ diff --git a/src/flint/types/qqbar.pxd b/src/flint/types/qqbar.pxd new file mode 100644 index 00000000..1c3ec34b --- /dev/null +++ b/src/flint/types/qqbar.pxd @@ -0,0 +1,33 @@ +from flint.flintlib.types.flint cimport slong +from flint.flintlib.functions.fmpz cimport fmpz_t +from flint.flintlib.functions.fmpq cimport fmpq_t + +cdef extern from "flint/qqbar.h" nogil: + ctypedef struct qqbar_struct: + pass + ctypedef qqbar_struct qqbar_t[1] + + # Lifecycle methods + void qqbar_init(qqbar_t res) + void qqbar_clear(qqbar_t res) + void qqbar_set(qqbar_t res, const qqbar_t x) + void qqbar_set_si(qqbar_t res, slong x) + + # Printing methods + void qqbar_print(const qqbar_t x) + void qqbar_printn(const qqbar_t x, slong n) + + # Interoperability setters + void qqbar_set_fmpz(qqbar_t res, const fmpz_t x) + void qqbar_set_fmpq(qqbar_t res, const fmpq_t x) + + # Arithmetic operations + void qqbar_add(qqbar_t res, const qqbar_t x, const qqbar_t y) + void qqbar_sub(qqbar_t res, const qqbar_t x, const qqbar_t y) + void qqbar_mul(qqbar_t res, const qqbar_t x, const qqbar_t y) + void qqbar_div(qqbar_t res, const qqbar_t x, const qqbar_t y) + +from flint.flint_base.flint_base cimport flint_scalar + +cdef class qqbar(flint_scalar): + cdef qqbar_t val diff --git a/src/flint/types/qqbar.pyx b/src/flint/types/qqbar.pyx new file mode 100644 index 00000000..f331415d --- /dev/null +++ b/src/flint/types/qqbar.pyx @@ -0,0 +1,80 @@ +from flint.types.fmpz cimport fmpz +from flint.types.fmpq cimport fmpq + +cdef class qqbar(flint_scalar): + """ + The qqbar class represents algebraic numbers. + """ + + def __cinit__(self): + qqbar_init(self.val) + + def __dealloc__(self): + qqbar_clear(self.val) + + def __init__(self, val=None): + if val is not None: + if isinstance(val, qqbar): + qqbar_set(self.val, (val).val) + elif isinstance(val, int): + qqbar_set_si(self.val, val) + elif isinstance(val, fmpz): + qqbar_set_fmpz(self.val, (val).val) + elif isinstance(val, fmpq): + qqbar_set_fmpq(self.val, (val).val) + else: + raise TypeError("Cannot initialize qqbar type from input") + + def str(self, Py_ssize_t digits=15): + """ + Converts the algebraic number to a decimal string representation. + """ + import sys + import io + + # Temporarily intercept stdout using a clean, cross-platform string buffer + old_stdout = sys.stdout + sys.stdout = io.StringIO() + + try: + qqbar_printn(self.val, digits) + sys.stdout.flush() + output = sys.stdout.getvalue() + finally: + sys.stdout = old_stdout + + return output.strip() + + def __str__(self): + return self.str() + + def __repr__(self): + return f"qqbar({self.str()})" + + def __add__(x, y): + cdef qqbar res = qqbar() + cdef qqbar c_x = x if isinstance(x, qqbar) else qqbar(x) + cdef qqbar c_y = y if isinstance(y, qqbar) else qqbar(y) + qqbar_add(res.val, c_x.val, c_y.val) + return res + + def __sub__(x, y): + cdef qqbar res = qqbar() + cdef qqbar c_x = x if isinstance(x, qqbar) else qqbar(x) + cdef qqbar c_y = y if isinstance(y, qqbar) else qqbar(y) + qqbar_sub(res.val, c_x.val, c_y.val) + return res + + def __mul__(x, y): + cdef qqbar res = qqbar() + cdef qqbar c_x = x if isinstance(x, qqbar) else qqbar(x) + cdef qqbar c_y = y if isinstance(y, qqbar) else qqbar(y) + qqbar_mul(res.val, c_x.val, c_y.val) + return res + + def __truediv__(x, y): + cdef qqbar res = qqbar() + cdef qqbar c_x = x if isinstance(x, qqbar) else qqbar(x) + cdef qqbar c_y = y if isinstance(y, qqbar) else qqbar(y) + qqbar_div(res.val, c_x.val, c_y.val) + return res