Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/aleaxit/gmpy
Browse files Browse the repository at this point in the history
  • Loading branch information
casevh committed Oct 13, 2023
2 parents 579f864 + ae60b07 commit 8c58be9
Show file tree
Hide file tree
Showing 29 changed files with 938 additions and 2,726 deletions.
4 changes: 2 additions & 2 deletions src/gmpy2_convert_gmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -589,10 +589,10 @@ GMPy_MPQ_From_PyStr(PyObject *s, int base, CTXT_Object *context)
*/

if (wheredot) {
char *counter;
unsigned char *counter;
long digits = 0;

counter = wheredot;
counter = (unsigned char*)wheredot;
digits = 0;
*wheredot = ' ';
while (*++counter != '\0') {
Expand Down
19 changes: 11 additions & 8 deletions src/gmpy2_format.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ static PyObject *
GMPy_MPZ_Format(PyObject *self, PyObject *args)
{
PyObject *result = NULL, *mpzstr = NULL;
char *fmtcode = 0, *p1, *p2;
char *fmtcode = 0;
unsigned char *p1, *p2;
char fmt[30];
int base = 10, option = 16;
int seensign = 0, seenindicator = 0, seenalign = 0, seendigits = 0;
Expand All @@ -72,8 +73,8 @@ GMPy_MPZ_Format(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "s", &fmtcode))
return NULL;

p2 = fmt;
for (p1 = fmtcode; *p1 != '\00'; p1++) {
p2 = (unsigned char*)fmt;
for (p1 = (unsigned char*)fmtcode; *p1 != '\00'; p1++) {
if (*p1 == '<' || *p1 == '>' || *p1 == '^') {
if (seenalign || seensign || seenindicator || seendigits) {
VALUE_ERROR("Invalid conversion specification");
Expand Down Expand Up @@ -201,7 +202,8 @@ static PyObject *
GMPy_MPFR_Format(PyObject *self, PyObject *args)
{
PyObject *result = NULL, *mpfrstr = NULL;
char *buffer = 0, *newbuf = 0, *fmtcode = 0, *p1, *p2, *p3;
char *buffer = 0, *newbuf = 0, *fmtcode = 0, *p2, *p3;
unsigned char *p1;
char mpfrfmt[100], fmt[30];
int buflen;
int seensign = 0, seenalign = 0, seendecimal = 0, seendigits = 0;
Expand All @@ -219,7 +221,7 @@ GMPy_MPFR_Format(PyObject *self, PyObject *args)
p3 = fmt;
*(p2++) = '%';

for (p1 = fmtcode; *p1 != '\00'; p1++) {
for (p1 = (unsigned char*)fmtcode; *p1 != '\00'; p1++) {
if (*p1 == '<' || *p1 == '>' || *p1 == '^') {
if (seenalign || seensign || seendecimal || seendigits || seenround) {
VALUE_ERROR("Invalid conversion specification");
Expand Down Expand Up @@ -380,7 +382,8 @@ GMPy_MPC_Format(PyObject *self, PyObject *args)
{
PyObject *result = NULL, *tempstr = NULL;
char *realbuf = 0, *imagbuf = 0, *tempbuf = 0, *fmtcode = 0;
char *p, *rfmtptr, *ifmtptr, *fmtptr;
char *rfmtptr, *fmtptr;
unsigned char *p, *ifmtptr;
char rfmt[100], ifmt[100], fmt[30];
int rbuflen, ibuflen;
int seensign = 0, seenalign = 0, seendecimal = 0, seendigits = 0;
Expand All @@ -396,12 +399,12 @@ GMPy_MPC_Format(PyObject *self, PyObject *args)
}

rfmtptr = rfmt;
ifmtptr = ifmt;
ifmtptr = (unsigned char*)ifmt;
fmtptr = fmt;
*(rfmtptr++) = '%';
*(ifmtptr++) = '%';

for (p = fmtcode; *p != '\00'; p++) {
for (p = (unsigned char*)fmtcode; *p != '\00'; p++) {
if (*p == '<' || *p == '>' || *p == '^') {
if (seenalign || seensign || seendecimal || seendigits ||
seenround || seenstyle) {
Expand Down
3 changes: 3 additions & 0 deletions test/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
import gmpy2


collect_ignore_glob = ['*.txt']


@pytest.fixture(autouse=True, scope='module')
def _set_default_context():
gmpy2.set_context(gmpy2.context())
13 changes: 3 additions & 10 deletions test/runtests.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,9 @@
mpq_doctests = ["test_mpq.txt"]

mpfr_doctests = ["test_mpfr_create.txt", "test_mpfr.txt",
"test_mpfr_trig.txt",
"test_context.txt", "test_mpfr_subnormalize.txt"]
"test_mpfr_trig.txt", "test_context.txt"]

# Some tests may differ between MPFR3 and MPFR4.
mpfr_major_version = gmpy2.mpfr_version().split()[1].split('.')[0]
mpfr_version_tests = [os.path.basename(i)
for i in glob.glob(os.path.join(test_dir,
"test_mpfr" + mpfr_major_version + "*.txt"))]

mpc_doctests = ["test_mpc.txt", "test_mpc_trig.txt"]
mpc_doctests = ["test_mpc.txt"]

gmpy2_tests = [os.path.basename(i)
for i in glob.glob(os.path.join(test_dir,
Expand All @@ -49,7 +42,7 @@

all_doctests = gmpy2_tests + mpz_doctests + mpq_doctests

all_doctests += mpfr_doctests + mpfr_version_tests
all_doctests += mpfr_doctests

all_doctests += mpc_doctests

Expand Down
71 changes: 70 additions & 1 deletion test/test_functions.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import pytest

import gmpy2
from gmpy2 import (root, rootn, zero, mpz, mpq, mpfr, mpc, is_nan, maxnum,
minnum)
minnum, fma, fms, ieee, fmma, fmms)


def test_root():
Expand Down Expand Up @@ -64,3 +65,71 @@ def test_minnum():
assert minnum(minf, a) == mpfr('-inf')
assert minnum(nan, inf) == mpfr('inf')
assert is_nan(minnum(nan, nan))


def test_fused():
assert fma(2,3,4) == mpz(10)
assert fma(2,3,-4) == mpz(2)
assert fma(2.0,3,-4) == mpfr('2.0')
assert fma(2,3.0,-4) == mpfr('2.0')
assert fma(2,3,-4.0) == mpfr('2.0')
assert fma(2,mpfr(3),-4.0) == mpfr('2.0')
assert fma(mpc(2),mpfr(3),-4.0) == mpc('2.0+0.0j')
assert fms(2,3,4) == mpz(2)
assert fms(2,3,-4) == mpz(10)

assert ieee(128).fma(7,1/7,-1) == mpfr('-5.55111512312578270211815834045410156e-17',113)
assert ieee(128).fma(7,mpq(1,7),-1) == mpq(0,1)

pytest.raises(TypeError, lambda: fma(1,2,"r"))

assert fma(1,2,mpq(3,4)) == mpq(11,4)
assert fms(1,2,mpq(3,4)) == mpq(5,4)
assert fms(1,mpfr(2),3) == mpfr('-1.0')
assert fms(1,mpc(2),3) == mpc('-1.0+0.0j')

assert fmma(2,3,4,5) == mpz(26)
assert fmma(2,3,-4,5) == mpz(-14)
assert fmma(2.0,3,-4, mpq(5)) == mpfr('-14.0')
assert fmma(2,3.0,-4,5) == mpfr('-14.0')
assert fmma(2,3,-4.0,5) == mpfr('-14.0')
assert fmma(2,mpfr(3),-4.0,5) == mpfr('-14.0')

pytest.raises(TypeError, lambda: fmma(mpc(2),mpfr(3),-4.0,5))

assert fmms(2,3,4,5) == mpz(-14)
assert fmms(2,3,-4,5) == mpz(26)
assert fmms(2, 3, mpq(1, 2), 5) == mpq(7,2)
assert fmms(2, 3, mpfr(1.2), 1) == mpfr('4.7999999999999998')

assert ieee(128).fmma(7,1/7,-1,3/11) == mpfr('0.727272727272727237401994671017746441',113)
assert ieee(128).fmma(7,mpq(1,7),-1,mpq(3,11)) == mpq(8,11)


def test_trigonometric():
assert gmpy2.acos(mpc(0.2, 0.2)) == mpc('1.3735541886535356-0.20256635782456389j')
assert gmpy2.acos(mpc(0.2, 0.2)) == gmpy2.acos(complex(0.2, 0.2))

assert gmpy2.asin(mpc(0.2,0.2)) == mpc('0.1972421381413611+0.20256635782456389j')
assert gmpy2.asin(mpc(2.0,0.2)) == mpc('1.4560834209500821+1.3245636864399635j')
assert gmpy2.asin(mpc(0.2,0.2)) == gmpy2.asin(complex(0.2,0.2))

assert gmpy2.atan(mpc(2.0, 2.0)) == mpc('1.311223269671635+0.23887786125685909j')
assert gmpy2.atan(mpc(2.0, 2.0)) == gmpy2.atan(complex(2.0, 2.0))

c = mpc(2,3)

assert gmpy2.cos(c) == mpc('-4.189625690968807-9.109227893755337j')

assert gmpy2.sin(c) == mpc('9.1544991469114301-4.1689069599665647j')

assert gmpy2.sin_cos(c) == (mpc('9.1544991469114301-4.1689069599665647j'), mpc('-4.189625690968807-9.109227893755337j'))
assert gmpy2.sin_cos(c) == gmpy2.sin_cos(complex(2,3))
assert gmpy2.sin_cos(c) == (gmpy2.sin(c), gmpy2.cos(c))

assert gmpy2.tan(mpc(4,5)) == mpc('8.9834776469715613e-05+1.0000132074347847j')

assert gmpy2.atanh(mpc(2.0, 3.0)) == mpc('0.14694666622552977+1.3389725222944935j')
assert gmpy2.atanh(mpc(2.0, 3.0)) == gmpy2.atanh(complex(2, 3))

assert gmpy2.tanh(mpc(4,5)) == mpc('1.0005630461157933-0.00036520305451130409j')
177 changes: 176 additions & 1 deletion test/test_generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

import pytest

from gmpy2 import mpz, mpq, mpfr, mpc, get_context, square, add
import gmpy2
from gmpy2 import mpz, mpq, mpfr, mpc, get_context, square, add, digits, xmpz
from supportclasses import z, q, r, cx


Expand Down Expand Up @@ -154,3 +155,177 @@ def test_add():
assert mpc(1,2) + r == mpc('2.5+2.0j')
assert mpc(1,2) + q == mpc('2.5+2.0j')
assert mpc(1,2) + z == mpc('3.0+2.0j')


def test_digits():
z2 = mpz(5)

pytest.raises(TypeError, lambda: digits())
pytest.raises(TypeError, lambda: digits(5, 5, 4, 5))

assert digits(z2) == '5'
assert digits(z2, 2) == '101'

pytest.raises(TypeError, lambda: digits(z2, 2, 5))

assert digits(mpq(3,5)) == '3/5'
assert digits(mpq(3,5), 4) == '3/11'
assert digits(mpfr(3,5), 4) == ('300', 1, 5)
assert digits(mpfr(3,5), 4, 5) == ('30000', 1, 5)
assert digits(complex(5,5), 4, 5) == (('11000', 2, 53), ('11000', 2, 53))

pytest.raises(TypeError, lambda: digits('string', 4, 5))


def test_abs():
a = mpz(123)
b = abs(a)

assert a is b

a = xmpz(123)
b = abs(a)

assert a is not b

a = mpz(-123)
b = abs(a)

assert b == mpz(123)
assert a is not b
assert a == mpz(-123)

a = mpq(12,7)
b = abs(a)

assert a is b

a = mpq(-12,7)
b = abs(a)

assert b == mpq(12,7)
assert a == mpq(-12,7)

a = xmpz(-123)
b = abs(a)

assert a == xmpz(123)
assert b is None

b = abs(a)

assert b is None

a = mpfr(1.0)
b = abs(a)

assert a is not b
assert abs(mpfr(1, precision=100)) == mpfr('1.0')

ctx = gmpy2.get_context()
ctx.clear_flags()

assert gmpy2.is_nan(abs(mpfr('nan')))
assert ctx.invalid

ctx.clear_flags()

assert abs(mpfr('inf')) == mpfr('inf')
assert ctx.overflow is False

ctx.clear_flags()

assert abs(mpfr('-inf')) == mpfr('inf')
assert ctx.overflow is False

assert abs(mpc(-1,0)) == mpfr('1.0')
assert abs(-1+0j) == 1.0
assert abs(mpc(1,1)) == mpfr('1.4142135623730951')

ctx = gmpy2.get_context()
ctx.clear_flags()

c = mpc('nan+0j')

assert gmpy2.is_nan(c.real) and c.imag == 0.0
assert ctx.invalid
assert gmpy2.is_nan(abs(c))
assert ctx.invalid

ctx.clear_flags()

assert gmpy2.is_nan(abs(mpc('nanj')))
assert ctx.invalid

ctx.clear_flags()

assert abs(mpc('inf+10j')) == mpfr('inf')
assert ctx.overflow is False

ctx.clear_flags()

assert abs(mpc('-infj')) == mpfr('inf')
assert ctx.overflow is False

a = mpc('nan+infj')
ctx.clear_flags()

assert abs(a) == mpfr('inf')
assert ctx.overflow is False
assert ctx.invalid is False

a=mpc('-inf+nanj')
ctx.clear_flags()

assert abs(a) == mpfr('inf')
assert ctx.overflow is False
assert ctx.invalid is False

ctx = gmpy2.context()

pytest.raises(TypeError, lambda: ctx.abs('a'))

assert ctx.abs(-1) == mpz(1)
assert ctx.abs(0) == mpz(0)
assert ctx.abs(1) == mpz(1)
assert ctx.abs(mpz(8)) == mpz(8)
assert ctx.abs(mpz(-8)) == mpz(8)
assert ctx.abs(-1.0) == mpfr('1.0')
assert ctx.abs(mpfr(-2)) == mpfr('2.0')
assert ctx.abs(2+3j) == mpfr('3.6055512754639891')
assert ctx.abs(mpc(2+3j)) == mpfr('3.6055512754639891')
assert ctx.abs(Fraction(1,2)) == mpq(1,2)
assert ctx.abs(Fraction(-1,2)) == mpq(1,2)


def test_muldiv_2exp():
ctx = gmpy2.get_context()
r = mpfr(7.6)
z = mpz(3)
c = mpc(4,4)

assert gmpy2.mul_2exp(r, z) == mpfr('60.799999999999997')
assert gmpy2.mul_2exp(r, 3) == mpfr('60.799999999999997')

pytest.raises(OverflowError, lambda: gmpy2.mul_2exp(r, -5))
pytest.raises(TypeError, lambda: gmpy2.mul_2exp(z, r))
pytest.raises(TypeError, lambda: gmpy2.mul_2exp('not', 5))
pytest.raises(TypeError, lambda: ctx.mul_2exp(r, z, 45))

assert ctx.mul_2exp(c, z) == mpc('32.0+32.0j')

pytest.raises(OverflowError, lambda: ctx.mul_2exp(c, -5))

assert ctx.mul_2exp(r, 0) == mpfr('7.5999999999999996')

assert gmpy2.div_2exp(r, z) == mpfr('0.94999999999999996')
assert gmpy2.div_2exp(r, 3) == mpfr('0.94999999999999996')

pytest.raises(OverflowError, lambda: gmpy2.div_2exp(r, -5))
pytest.raises(TypeError, lambda: gmpy2.div_2exp(z, r))
pytest.raises(TypeError, lambda: gmpy2.div_2exp('not', 5))
pytest.raises(TypeError, lambda: ctx.div_2exp(r, z, 45))

assert ctx.div_2exp(c, z) == mpc('0.5+0.5j')

pytest.raises(OverflowError, lambda: ctx.div_2exp(c, -5))
Loading

0 comments on commit 8c58be9

Please sign in to comment.