qpq_t element assignment functionality

Former-commit-id: 63edc3b1f27209af18932f6fd8f284c1859eb40d
This commit is contained in:
Marek Nečada 2019-10-19 14:34:09 +03:00
parent a4df0139b9
commit 25d1eced26
3 changed files with 104 additions and 7 deletions

23
qpms/cypolynomials.pxd Normal file
View File

@ -0,0 +1,23 @@
cdef extern from "<gmp.h>":
cdef struct __mpq_struct:
pass
ctypedef __mpq_struct mpq_t[1]
cdef struct __mpz_struct:
pass
ctypedef __mpz_struct mpz_t[1]
double mpz_get_d(const mpz_t op)
cdef extern from "polynomials.h":
cdef struct qpq_t:
int order
int offset
int capacity
mpq_t *coeffs
void qpq_init(qpq_t *x, int capacity)
void qpq_extend(qpq_t *x, int new_capacity)
void qpq_set(qpq_t *copy, const qpq_t *orig)
void qpq_clear(qpq_t

View File

@ -6,6 +6,15 @@
#define MAX(x, y) (((x) > (y)) ? (x) : (y)) #define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define MIN(x, y) (((x) <= (y)) ? (x) : (y)) #define MIN(x, y) (((x) <= (y)) ? (x) : (y))
// Auxillary function to set a mpq_t to 0/1
static inline void mpq_zero(mpq_t q) {
// Maybe not the best way to set it to zero.
// Alternatively, we could use just mpz_set_si(mpq_numref(sum->coeffs[i - minoffset]), 0);
mpq_clear(q);
mpq_init(q);
}
// qpq_t internal consistency check // qpq_t internal consistency check
static inline void qpq_cc(const qpq_t *p) { static inline void qpq_cc(const qpq_t *p) {
if (!p->coeffs) return; if (!p->coeffs) return;
@ -41,6 +50,70 @@ void qpq_extend(qpq_t *p, int cap) {
} }
} }
void qpq_set(qpq_t *p, const qpq_t *orig) {
const int order = orig->order, offset = orig->offset;
qpq_extend(p, order - offset + 1);
for (int i = orig->offset; i <= order; ++i)
mpq_set(p->coeffs[i - offset], orig->coeffs[i - offset]);
p->offset = offset;
p->order = order;
return;
}
void qpq_set_elem(qpq_t *p, const int exponent, const mpq_t coeff) {
QPMS_ENSURE(exponent >= 0, "Exponent must be non-negative, got %d", exponent);
int offset = p->offset, order = p->order;
if(mpq_sgn(coeff) == 0 && (exponent < offset || exponent > order))
return; // exponent out of range, but zero needs not to be assigned explicitly
if(exponent < p->offset) {
qpq_extend(p, p->order - exponent + 1);
offset = exponent;
for(int i = order - offset; i >= p->offset - offset; --i)
mpq_swap(p->coeffs[i], p->coeffs[i - (p->offset - offset)]);
for(int i = p->offset - offset - 1; i > 0; --i)
mpq_zero(p->coeffs[i]);
p->offset = offset;
}
if(exponent > order) {
qpq_extend(p, exponent - p->offset + 1);
for(int i = p->order - p->offset + 1; i <= exponent - p->offset; ++i)
mpq_zero(p->coeffs[i]);
p->order = exponent;
}
mpq_set(p->coeffs[exponent - p->offset], coeff);
return;
}
void qpq_set_elem_si(qpq_t *p, const int exponent, const long int num, const unsigned long int den) {
mpq_t q;
mpq_init(q);
mpq_set_si(q, num, den);
qpq_set_elem(p, exponent, q);
mpq_clear(q);
}
void qpq_get_elem(mpq_t coeff, const qpq_t *p, const int exponent) {
if (exponent < p->offset || exponent > p->order)
mpq_zero(coeff);
else
mpq_set(coeff, p->coeffs[exponent-p->offset]);
}
int qpq_get_elem_si(long *num, unsigned long *den, const qpq_t *p, const int exponent) {
mpq_t q;
mpq_init(q);
qpq_get_elem(q, p, exponent);
int retval = 0;
*num = mpz_get_si(mpq_numref(q));
if (!mpz_fits_slong_p(mpq_numref(q)))
retval += 1;
*den = mpz_get_ui(mpq_denref(q));
if (!mpz_fits_ulong_p(mpq_denref(q)))
retval += 2;
mpq_clear(q);
return retval;
}
void qpq_clear(qpq_t *p) { void qpq_clear(qpq_t *p) {
if (p->capacity > 0) { if (p->capacity > 0) {
for (int i = p->capacity; i >= 0; --i) for (int i = p->capacity; i >= 0; --i)
@ -65,10 +138,7 @@ void qpq_add(qpq_t *sum, const qpq_t *x, const qpq_t *y) {
if (i - y->offset >= 0 && i <= y->order) if (i - y->offset >= 0 && i <= y->order)
mpq_set(sum->coeffs[i - minoffset], y->coeffs[i - x->offset]); mpq_set(sum->coeffs[i - minoffset], y->coeffs[i - x->offset]);
else { else {
// Maybe not the best way to set it to zero. mpq_zero(sum->coeffs[i - minoffset]);
// Alternatively, we could use just mpz_set_si(mpq_numref(sum->coeffs[i - minoffset]), 0);
mpq_clear(sum->coeffs[i - minoffset]);
mpq_init(sum->coeffs[i - minoffset]);
} }
} }
} }
@ -92,9 +162,7 @@ void qpq_sub(qpq_t *dif, const qpq_t *x, const qpq_t *y) {
mpq_set(dif->coeffs[i - minoffset], y->coeffs[i - x->offset]); mpq_set(dif->coeffs[i - minoffset], y->coeffs[i - x->offset]);
mpq_neg(dif->coeffs[i - minoffset], dif->coeffs[i - minoffset]); mpq_neg(dif->coeffs[i - minoffset], dif->coeffs[i - minoffset]);
} else { } else {
// Maybe not the best way to set it to zero. mpq_zero(dif->coeffs[i - minoffset]);
mpq_clear(dif->coeffs[i - minoffset]);
mpq_init(dif->coeffs[i - minoffset]);
} }
} }
} }

View File

@ -33,6 +33,12 @@ void qpq_extend(qpq_t *x, int new_capacity);
void qpq_set(qpq_t *copy, const qpq_t *orig); void qpq_set(qpq_t *copy, const qpq_t *orig);
void qpq_set_elem(qpq_t *x, int exponent, const mpq_t coeff);
void qpq_set_elem_si(qpq_t *x, int exponent, long numerator, unsigned long denominator);
void qpq_get_elem(mpq_t coeff, const qpq_t *x, int exponent);
/** \returns zero if the result fits into long / unsigned long; non-zero otherwise. */
int qpq_get_elem_si(long *numerator, unsigned long *denominator, const qpq_t *x, int exponent);
/// Deinitialise the coefficients array in qpq_t. /// Deinitialise the coefficients array in qpq_t.
void qpq_clear(qpq_t *x); void qpq_clear(qpq_t *x);