python-gmp 0.6.0a0__tar.gz → 0.6.0a1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. {python_gmp-0.6.0a0 → python_gmp-0.6.0a1}/.readthedocs.yaml +1 -1
  2. {python_gmp-0.6.0a0 → python_gmp-0.6.0a1}/PKG-INFO +2 -2
  3. {python_gmp-0.6.0a0 → python_gmp-0.6.0a1}/README.rst +1 -1
  4. {python_gmp-0.6.0a0 → python_gmp-0.6.0a1}/bench/collatz.py +12 -1
  5. {python_gmp-0.6.0a0 → python_gmp-0.6.0a1}/bench/mul.py +2 -0
  6. {python_gmp-0.6.0a0 → python_gmp-0.6.0a1}/gmp.c +237 -270
  7. {python_gmp-0.6.0a0 → python_gmp-0.6.0a1}/scripts/cibw_before_all.sh +1 -1
  8. {python_gmp-0.6.0a0 → python_gmp-0.6.0a1}/tests/conftest.py +1 -1
  9. {python_gmp-0.6.0a0 → python_gmp-0.6.0a1}/tests/test_mpz.py +16 -9
  10. {python_gmp-0.6.0a0 → python_gmp-0.6.0a1}/.backportrc.json +0 -0
  11. {python_gmp-0.6.0a0 → python_gmp-0.6.0a1}/.clang-format +0 -0
  12. {python_gmp-0.6.0a0 → python_gmp-0.6.0a1}/.github/dependabot.yml +0 -0
  13. {python_gmp-0.6.0a0 → python_gmp-0.6.0a1}/.github/workflows/backport.yml +0 -0
  14. {python_gmp-0.6.0a0 → python_gmp-0.6.0a1}/.github/workflows/ci.yml +0 -0
  15. {python_gmp-0.6.0a0 → python_gmp-0.6.0a1}/.github/workflows/coverage.yml +0 -0
  16. {python_gmp-0.6.0a0 → python_gmp-0.6.0a1}/.github/workflows/linter.yml +0 -0
  17. {python_gmp-0.6.0a0 → python_gmp-0.6.0a1}/.github/workflows/publish.yml +0 -0
  18. {python_gmp-0.6.0a0 → python_gmp-0.6.0a1}/.github/workflows/wheels.yml +0 -0
  19. {python_gmp-0.6.0a0 → python_gmp-0.6.0a1}/.gitignore +0 -0
  20. {python_gmp-0.6.0a0 → python_gmp-0.6.0a1}/.pre-commit-config.yaml +0 -0
  21. {python_gmp-0.6.0a0 → python_gmp-0.6.0a1}/LICENSE +0 -0
  22. {python_gmp-0.6.0a0 → python_gmp-0.6.0a1}/bench/README.rst +0 -0
  23. {python_gmp-0.6.0a0 → python_gmp-0.6.0a1}/docs/conf.py +0 -0
  24. {python_gmp-0.6.0a0 → python_gmp-0.6.0a1}/docs/index.rst +0 -0
  25. {python_gmp-0.6.0a0 → python_gmp-0.6.0a1}/fmt.c +0 -0
  26. {python_gmp-0.6.0a0 → python_gmp-0.6.0a1}/meson.build +0 -0
  27. {python_gmp-0.6.0a0 → python_gmp-0.6.0a1}/mpz.h +0 -0
  28. {python_gmp-0.6.0a0 → python_gmp-0.6.0a1}/pyproject.toml +0 -0
  29. {python_gmp-0.6.0a0 → python_gmp-0.6.0a1}/pythoncapi_compat.h +0 -0
  30. {python_gmp-0.6.0a0 → python_gmp-0.6.0a1}/scripts/dll-importexport.diff +0 -0
  31. {python_gmp-0.6.0a0 → python_gmp-0.6.0a1}/scripts/fat_build_fix.diff +0 -0
  32. {python_gmp-0.6.0a0 → python_gmp-0.6.0a1}/scripts/gcc15.diff +0 -0
  33. {python_gmp-0.6.0a0 → python_gmp-0.6.0a1}/scripts/gitversion.py +0 -0
  34. {python_gmp-0.6.0a0 → python_gmp-0.6.0a1}/tests/test_functions.py +0 -0
  35. {python_gmp-0.6.0a0 → python_gmp-0.6.0a1}/tests/utils.py +0 -0
  36. {python_gmp-0.6.0a0 → python_gmp-0.6.0a1}/utils.c +0 -0
  37. {python_gmp-0.6.0a0 → python_gmp-0.6.0a1}/utils.h +0 -0
@@ -12,7 +12,7 @@ build:
12
12
  pre_create_environment:
13
13
  - |
14
14
  PREFIX=$(pwd)/.local
15
- ZZ_VERSION=0.8.0
15
+ ZZ_VERSION=0.9.0a4
16
16
  ZZ_DIR=zz-${ZZ_VERSION}
17
17
  GITHUB_URL=https://github.com/diofant/zz/releases/download/
18
18
  ZZ_URL=${GITHUB_URL}v${ZZ_VERSION}/${ZZ_DIR}.tar.gz
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-gmp
3
- Version: 0.6.0a0
3
+ Version: 0.6.0a1
4
4
  Summary: Safe bindings to the GNU GMP library
5
5
  Keywords: gmp,multiple-precision,arbitrary-precision,bignum
6
6
  Author-Email: Sergey B Kirpichev <skirpichev@gmail.com>
@@ -53,7 +53,7 @@ Python-GMP
53
53
  ==========
54
54
 
55
55
  Python extension module, providing bindings to the GNU GMP via the `ZZ library
56
- <https://github.com/diofant/zz>`_ (version 0.8.0 or later required). This
56
+ <https://github.com/diofant/zz>`_ (version 0.9.0 or later required). This
57
57
  module shouldn't crash the interpreter.
58
58
 
59
59
  The gmp can be used as a `gmpy2`_/`python-flint`_ replacement to provide
@@ -2,7 +2,7 @@ Python-GMP
2
2
  ==========
3
3
 
4
4
  Python extension module, providing bindings to the GNU GMP via the `ZZ library
5
- <https://github.com/diofant/zz>`_ (version 0.8.0 or later required). This
5
+ <https://github.com/diofant/zz>`_ (version 0.9.0 or later required). This
6
6
  module shouldn't crash the interpreter.
7
7
 
8
8
  The gmp can be used as a `gmpy2`_/`python-flint`_ replacement to provide
@@ -8,6 +8,8 @@ if os.getenv("T") == "gmpy2.mpz":
8
8
  from gmpy2 import mpz
9
9
  elif os.getenv("T") == "flint.fmpz":
10
10
  from flint import fmpz as mpz
11
+ elif os.getenv("T") == "int":
12
+ mpz = int
11
13
  else:
12
14
  from gmp import mpz
13
15
 
@@ -34,8 +36,17 @@ def collatz1(n):
34
36
  total += 1
35
37
  return total
36
38
 
39
+ def collatz2(n):
40
+ total = 0
41
+ n = mpz(n)
42
+ while n > 1:
43
+ n = n*3 + 1 if n & one else n//2
44
+ total += 1
45
+ return total
46
+
47
+
37
48
  runner = pyperf.Runner()
38
- for f in [collatz0, collatz1]:
49
+ for f in [collatz0, collatz1, collatz2]:
39
50
  for v in ["97", "871", "(1<<128)+31"]:
40
51
  h = f"{f.__name__}({v})"
41
52
  i = eval(v)
@@ -9,6 +9,8 @@ if os.getenv("T") == "gmpy2.mpz":
9
9
  from gmpy2 import mpz
10
10
  elif os.getenv("T") == "flint.fmpz":
11
11
  from flint import fmpz as mpz
12
+ elif os.getenv("T") == "int":
13
+ mpz = int
12
14
  else:
13
15
  from gmp import mpz
14
16
 
@@ -12,7 +12,7 @@
12
12
  #else
13
13
  # define MAX_CACHE_SIZE 0
14
14
  #endif
15
- #define MAX_CACHED_NDIGITS 16
15
+ #define MAX_CACHED_SIZEOF 256
16
16
 
17
17
  typedef struct {
18
18
  MPZ_Object *gmp_cache[MAX_CACHE_SIZE + 1];
@@ -56,7 +56,7 @@ int OPT_PREFIX = 0x2;
56
56
  PyObject *
57
57
  MPZ_to_str(MPZ_Object *u, int base, int options)
58
58
  {
59
- size_t len;
59
+ size_t len = 0;
60
60
  bool negative = zz_isneg(&u->z);
61
61
 
62
62
  if (zz_sizeinbase(&u->z, base, &len)) {
@@ -140,60 +140,11 @@ MPZ_from_str(PyObject *obj, int base)
140
140
  if (!str) {
141
141
  return NULL; /* LCOV_EXCL_LINE */
142
142
  }
143
- if (base < 0) {
144
- goto bad_base;
145
- }
146
143
 
147
144
  MPZ_Object *res = MPZ_new();
148
145
 
149
146
  if (!res) {
150
- return (MPZ_Object *)PyErr_NoMemory(); /* LCOV_EXCL_LINE */
151
- }
152
- while (isspace(*str)) {
153
- str++;
154
- }
155
-
156
- bool cast_negative = (str[0] == '-');
157
-
158
- str += cast_negative;
159
- if (str[0] == '+') {
160
- str++;
161
- }
162
- if (str[0] == '0') {
163
- if (base == 0) {
164
- if (tolower(str[1]) == 'b') {
165
- base = 2;
166
- }
167
- else if (tolower(str[1]) == 'o') {
168
- base = 8;
169
- }
170
- else if (tolower(str[1]) == 'x') {
171
- base = 16;
172
- }
173
- else if (!isspace(str[1]) && str[1] != '\0') {
174
- goto err;
175
- }
176
- }
177
- if ((tolower(str[1]) == 'b' && base == 2)
178
- || (tolower(str[1]) == 'o' && base == 8)
179
- || (tolower(str[1]) == 'x' && base == 16))
180
- {
181
- str += 2;
182
- if (str[0] == '_') {
183
- str++;
184
- }
185
- }
186
- else {
187
- goto skip_negation;
188
- }
189
- }
190
- else {
191
- skip_negation:
192
- str -= cast_negative;
193
- cast_negative = false;
194
- }
195
- if (base == 0) {
196
- base = 10;
147
+ return NULL; /* LCOV_EXCL_LINE */
197
148
  }
198
149
 
199
150
  zz_err ret = zz_set_str(str, base, &res->z);
@@ -204,24 +155,26 @@ skip_negation:
204
155
  return (MPZ_Object *)PyErr_NoMemory();
205
156
  /* LCOV_EXCL_STOP */
206
157
  }
158
+ else if (ret == ZZ_BUF) {
159
+ /* LCOV_EXCL_START */
160
+ PyErr_SetString(PyExc_OverflowError,
161
+ "too many digits in integer");
162
+ return NULL;
163
+ /* LCOV_EXCL_STOP */
164
+ }
207
165
  else if (ret == ZZ_VAL) {
208
166
  Py_DECREF(res);
209
- if (2 <= base && base <= 36) {
210
- err:
167
+ if (!base || (2 <= base && base <= 36)) {
211
168
  PyErr_Format(PyExc_ValueError,
212
169
  "invalid literal for mpz() with base %d: %.200R",
213
170
  base, obj);
214
171
  }
215
172
  else {
216
- bad_base:
217
173
  PyErr_SetString(PyExc_ValueError,
218
174
  "mpz base must be >= 2 and <= 36, or 0");
219
175
  }
220
176
  return NULL;
221
177
  }
222
- if (cast_negative) {
223
- (void)zz_neg(&res->z, &res->z);
224
- }
225
178
  return res;
226
179
  }
227
180
 
@@ -239,10 +192,22 @@ MPZ_from_int(PyObject *obj)
239
192
  }
240
193
  if (long_export.digits) {
241
194
  res = MPZ_new();
242
- if (!res || zz_import((size_t)long_export.ndigits,
243
- long_export.digits, *int_layout, &res->z))
244
- {
245
- return (MPZ_Object *)PyErr_NoMemory(); /* LCOV_EXCL_LINE */
195
+ if (!res) {
196
+ return NULL; /* LCOV_EXCL_LINE */
197
+ }
198
+
199
+ zz_err ret = zz_import((size_t)long_export.ndigits,
200
+ long_export.digits, *int_layout, &res->z);
201
+
202
+ if (ret) {
203
+ /* LCOV_EXCL_START */
204
+ if (ret == ZZ_MEM) {
205
+ return (MPZ_Object *)PyErr_NoMemory();
206
+ }
207
+ PyErr_SetString(PyExc_OverflowError,
208
+ "too many digits in integer");
209
+ return NULL;
210
+ /* LCOV_EXCL_STOP */
246
211
  }
247
212
  if (long_export.negative) {
248
213
  (void)zz_neg(&res->z, &res->z);
@@ -316,7 +281,7 @@ MPZ_to_int(MPZ_Object *u)
316
281
  if (zz_get_str(&u->z, 16, buf)) {
317
282
  /* LCOV_EXCL_START */
318
283
  free(buf);
319
- return NULL;
284
+ return PyErr_NoMemory();
320
285
  /* LCOV_EXCL_STOP */
321
286
  }
322
287
 
@@ -383,7 +348,7 @@ zz_get_bytes(const zz_t *u, size_t length, bool is_signed,
383
348
 
384
349
  size_t gap = length - (nbits + bits_per_digit/8 - 1)/(bits_per_digit/8);
385
350
 
386
- zz_export(u, bytes_layout, length - gap, *buffer + gap);
351
+ (void)zz_export(u, bytes_layout, length - gap, *buffer + gap);
387
352
  memset(*buffer, is_negative ? 0xFF : 0, gap);
388
353
  zz_clear(&tmp);
389
354
  return ZZ_OK;
@@ -437,13 +402,18 @@ zz_set_bytes(const unsigned char *buffer, size_t length, bool is_signed,
437
402
  if (!length) {
438
403
  return zz_set(0, u);
439
404
  }
440
- if (zz_import(length, buffer, bytes_layout, u)) {
441
- return ZZ_MEM; /* LCOV_EXCL_LINE */
405
+
406
+ zz_err ret = zz_import(length, buffer, bytes_layout, u);
407
+
408
+ if (ret) {
409
+ return ret; /* LCOV_EXCL_LINE */
442
410
  }
443
411
  (void)zz_abs(u, u);
444
412
  if (is_signed && zz_bitlen(u) == 8*(size_t)length) {
445
413
  zz_t tmp;
446
414
 
415
+ /* we assume, that bytes were created by zz_get_bytes(),
416
+ else there could be overflow in zz_mul_2exp() */
447
417
  if (zz_init(&tmp) || zz_set(1, &tmp)
448
418
  || zz_mul_2exp(&tmp, 8*length, &tmp)
449
419
  || zz_sub(&tmp, u, u) || zz_neg(u, u))
@@ -490,19 +460,33 @@ MPZ_from_bytes(PyObject *obj, int is_little, int is_signed)
490
460
 
491
461
  MPZ_Object *res = MPZ_new();
492
462
 
493
- if (!res || zz_set_bytes(buffer, (size_t)length, is_signed, &res->z)) {
463
+ if (!res) {
494
464
  /* LCOV_EXCL_START */
495
465
  Py_DECREF(bytes);
496
466
  if (is_little) {
497
467
  free(buffer);
498
468
  }
499
- Py_XDECREF((PyObject *)res);
500
- return (MPZ_Object *)PyErr_NoMemory();
469
+ return NULL;
501
470
  /* LCOV_EXCL_STOP */
502
471
  }
472
+
473
+ zz_err ret = zz_set_bytes(buffer, (size_t)length, is_signed, &res->z);
474
+
475
+ Py_DECREF(bytes);
503
476
  if (is_little) {
504
477
  free(buffer);
505
478
  }
479
+ if (ret) {
480
+ /* LCOV_EXCL_START */
481
+ Py_DECREF((PyObject *)res);
482
+ if (ret == ZZ_MEM) {
483
+ return (MPZ_Object *)PyErr_NoMemory();
484
+ }
485
+ PyErr_SetString(PyExc_OverflowError,
486
+ "too many digits in integer");
487
+ return NULL;
488
+ /* LCOV_EXCL_STOP */
489
+ }
506
490
  return res;
507
491
  }
508
492
 
@@ -676,7 +660,7 @@ dealloc(PyObject *self)
676
660
  MPZ_Object *u = (MPZ_Object *)self;
677
661
 
678
662
  if (global.gmp_cache_size < MAX_CACHE_SIZE
679
- && (u->z).alloc <= MAX_CACHED_NDIGITS
663
+ && zz_sizeof(&u->z) <= MAX_CACHED_SIZEOF
680
664
  && MPZ_CheckExact(self))
681
665
  {
682
666
  global.gmp_cache[global.gmp_cache_size++] = u;
@@ -866,14 +850,20 @@ hash(PyObject *self)
866
850
  return u->hash_cache;
867
851
  }
868
852
 
869
- zz_digit_t digits[1];
870
- zz_t w = {false, 1, 1, digits};
853
+ zz_t w;
854
+
855
+ if (zz_init(&w)) {
856
+ return -1; /* LCOV_EXCL_LINE */
857
+ }
871
858
 
872
859
  assert((int64_t)INT64_MAX > pyhash_modulus);
873
860
  (void)zz_div(&u->z, (int64_t)pyhash_modulus, NULL, &w);
874
861
 
875
- Py_hash_t r = w.size ? (Py_hash_t)w.digits[0] : 0;
862
+ Py_hash_t r;
876
863
 
864
+ assert(sizeof(Py_hash_t) == 8);
865
+ (void)zz_get(&w, (int64_t *)&r);
866
+ zz_clear(&w);
877
867
  if (zz_isneg(&u->z) && r) {
878
868
  r = -(pyhash_modulus - r);
879
869
  }
@@ -883,23 +873,36 @@ hash(PyObject *self)
883
873
  return u->hash_cache = r;
884
874
  }
885
875
 
886
- #define UNOP(suff, func) \
887
- static PyObject * \
888
- func(PyObject *self) \
889
- { \
890
- MPZ_Object *u = (MPZ_Object *)self; \
891
- MPZ_Object *res = MPZ_new(); \
892
- \
893
- if (res && zz_##suff(&u->z, &res->z)) { \
894
- PyErr_NoMemory(); /* LCOV_EXCL_LINE */ \
895
- } \
896
- return (PyObject *)res; \
876
+ #define UNOP(suff, func) \
877
+ static PyObject * \
878
+ func(PyObject *self) \
879
+ { \
880
+ MPZ_Object *u = (MPZ_Object *)self; \
881
+ MPZ_Object *res = MPZ_new(); \
882
+ \
883
+ if (!res) { \
884
+ return NULL; \
885
+ } \
886
+ \
887
+ zz_err ret = zz_##suff(&u->z, &res->z); \
888
+ \
889
+ if (ret) { \
890
+ Py_CLEAR(res); \
891
+ if (ret == ZZ_BUF) { \
892
+ PyErr_SetString(PyExc_OverflowError, \
893
+ "too many digits in integer"); \
894
+ } \
895
+ else { \
896
+ PyErr_NoMemory(); \
897
+ } \
898
+ } \
899
+ return (PyObject *)res; \
897
900
  }
898
901
 
899
902
  UNOP(pos, plus)
900
903
  UNOP(neg, nb_negative)
901
904
  UNOP(abs, nb_absolute)
902
- UNOP(invert, nb_invert)
905
+ UNOP(invert, nb_invert) /* may overflow */
903
906
 
904
907
  PyObject *
905
908
  to_int(PyObject *self)
@@ -972,17 +975,19 @@ to_bool(PyObject *self)
972
975
  } \
973
976
  ret = zz_##suff(&u->z, &v->z, &res->z); \
974
977
  done: \
975
- if (ret == ZZ_OK) { \
976
- goto end; \
977
- } \
978
- if (ret == ZZ_VAL) { \
979
- Py_CLEAR(res); \
980
- PyErr_SetString(PyExc_ZeroDivisionError, \
981
- "division by zero"); \
982
- } \
983
- else { \
978
+ if (ret) { \
984
979
  Py_CLEAR(res); \
985
- PyErr_NoMemory(); \
980
+ if (ret == ZZ_VAL) { \
981
+ PyErr_SetString(PyExc_ZeroDivisionError, \
982
+ "division by zero"); \
983
+ } \
984
+ else if (ret == ZZ_BUF) { \
985
+ PyErr_SetString(PyExc_OverflowError, \
986
+ "too many digits in integer"); \
987
+ } \
988
+ else { \
989
+ PyErr_NoMemory(); \
990
+ } \
986
991
  } \
987
992
  end: \
988
993
  Py_XDECREF((PyObject *)u); \
@@ -1032,6 +1037,7 @@ BINOP(mul, PyNumber_Multiply)
1032
1037
  #define zz_quo_(u, v, w) zz_div((u), (v), (w), NULL)
1033
1038
  #define zz_rem_(u, v, w) zz_div((u), (v), NULL, (w))
1034
1039
 
1040
+ /* can't overflow */
1035
1041
  BINOP(quo_, PyNumber_FloorDivide)
1036
1042
  BINOP(rem_, PyNumber_Remainder)
1037
1043
 
@@ -1149,6 +1155,8 @@ err:
1149
1155
  if (cmp == ZZ_EQ && !zz_isodd(v) && !zz_iszero(q) && zz_isodd(q)) {
1150
1156
  cmp = unexpect;
1151
1157
  }
1158
+ /* No overflow is possible, since q can't have maximal value
1159
+ below (that means v==1) and r have same sign as v (with |r| < |v|) */
1152
1160
  if (cmp == unexpect && (zz_add(q, 1, q) || zz_sub(r, v, r))) {
1153
1161
  goto err; /* LCOV_EXCL_LINE */
1154
1162
  }
@@ -1231,6 +1239,8 @@ tmp_clear:
1231
1239
  }
1232
1240
  }
1233
1241
  shift += DBL_MANT_DIG;
1242
+ /* No overflow is possible in shifts, since shift value
1243
+ much smaller here than zz_get_bitcnt_max() */
1234
1244
  if (shift > 0 && zz_mul_2exp(&a, (uint64_t)shift, &a)) {
1235
1245
  goto tmp_clear; /* LCOV_EXCL_LINE */
1236
1246
  }
@@ -1339,18 +1349,6 @@ numbers:
1339
1349
  } \
1340
1350
  } \
1341
1351
 
1342
- #define CHECK_OP_INTv2(u, a) \
1343
- if (MPZ_Check(a)) { \
1344
- u = (MPZ_Object *)a; \
1345
- Py_INCREF(u); \
1346
- } \
1347
- else if (PyLong_Check(a)) { \
1348
- ; \
1349
- } \
1350
- else { \
1351
- goto end; \
1352
- } \
1353
-
1354
1352
  #define BINOP_INT(suff) \
1355
1353
  static PyObject * \
1356
1354
  nb_##suff(PyObject *self, PyObject *other) \
@@ -1363,7 +1361,7 @@ numbers:
1363
1361
  res = MPZ_new(); \
1364
1362
  zz_err ret = ZZ_OK; \
1365
1363
  \
1366
- if (!res || (ret = zz_##suff(&u->z, &v->z, &res->z))) { \
1364
+ if (res && (ret = zz_##suff(&u->z, &v->z, &res->z))) { \
1367
1365
  /* LCOV_EXCL_START */ \
1368
1366
  Py_CLEAR(res); \
1369
1367
  if (ret == ZZ_VAL) { \
@@ -1385,90 +1383,7 @@ numbers:
1385
1383
  return (PyObject *)res; \
1386
1384
  }
1387
1385
 
1388
- #define BINOP_INTv2(suff) \
1389
- static PyObject * \
1390
- nb_##suff(PyObject *self, PyObject *other) \
1391
- { \
1392
- MPZ_Object *u = NULL, *v = NULL, *res = NULL; \
1393
- \
1394
- CHECK_OP_INTv2(u, self); \
1395
- CHECK_OP_INTv2(v, other); \
1396
- \
1397
- res = MPZ_new(); \
1398
- if (!res) { \
1399
- goto end; \
1400
- } \
1401
- \
1402
- zz_err ret = ZZ_OK; \
1403
- \
1404
- if (!u) { \
1405
- int error = PyLong_IsNegative(self) || zz_isneg(&v->z); \
1406
- \
1407
- if (!error) { \
1408
- int64_t temp = PyLong_AsSdigit_t(self, &error); \
1409
- \
1410
- if (!error) { \
1411
- ret = zz_i64_##suff(temp, &v->z, &res->z); \
1412
- goto done; \
1413
- } \
1414
- } \
1415
- u = MPZ_from_int(self); \
1416
- if (!u) { \
1417
- goto end; \
1418
- } \
1419
- } \
1420
- if (!v) { \
1421
- int error = zz_isneg(&u->z) || PyLong_IsNegative(other); \
1422
- \
1423
- if (!error) { \
1424
- int64_t temp = PyLong_AsSdigit_t(other, &error); \
1425
- \
1426
- if (!error) { \
1427
- ret = zz_##suff##_i64(&u->z, temp, &res->z); \
1428
- goto done; \
1429
- } \
1430
- } \
1431
- v = MPZ_from_int(other); \
1432
- if (!v) { \
1433
- goto end; \
1434
- } \
1435
- } \
1436
- ret = zz_##suff(&u->z, &v->z, &res->z); \
1437
- done: \
1438
- if (ret) { \
1439
- /* LCOV_EXCL_START */ \
1440
- Py_CLEAR(res); \
1441
- if (ret == ZZ_VAL) { \
1442
- PyErr_SetString(PyExc_ValueError, \
1443
- "negative shift count"); \
1444
- } \
1445
- else if (ret == ZZ_BUF) { \
1446
- PyErr_SetString(PyExc_OverflowError, \
1447
- "too many digits in integer"); \
1448
- } \
1449
- else { \
1450
- PyErr_NoMemory(); \
1451
- } \
1452
- /* LCOV_EXCL_STOP */ \
1453
- } \
1454
- end: \
1455
- Py_XDECREF((PyObject *)u); \
1456
- Py_XDECREF((PyObject *)v); \
1457
- return (PyObject *)res; \
1458
- }
1459
-
1460
- static inline zz_err
1461
- zz_and_i64(const zz_t *u, int64_t v, zz_t *w)
1462
- {
1463
- if (zz_iszero(u) || !v) {
1464
- return zz_set(0, w);
1465
- }
1466
- assert(!zz_isneg(u) && v > 0);
1467
- return zz_set((int64_t)(u->digits[0] & (zz_digit_t)v), w);
1468
- }
1469
- #define zz_i64_and(x, y, r) zz_and_i64((y), (x), (r))
1470
-
1471
- BINOP_INTv2(and)
1386
+ BINOP_INT(and)
1472
1387
  BINOP_INT(or)
1473
1388
  BINOP_INT(xor)
1474
1389
 
@@ -1479,12 +1394,12 @@ zz_lshift(const zz_t *u, const zz_t *v, zz_t *w)
1479
1394
  return ZZ_VAL;
1480
1395
  }
1481
1396
 
1482
- int64_t shift;
1397
+ uint64_t shift;
1483
1398
 
1484
1399
  if (zz_get(v, &shift)) {
1485
1400
  return ZZ_BUF;
1486
1401
  }
1487
- return zz_mul_2exp(u, (zz_bitcnt_t)shift, w);
1402
+ return zz_mul_2exp(u, shift, w);
1488
1403
  }
1489
1404
 
1490
1405
  static inline zz_err
@@ -1494,12 +1409,12 @@ zz_rshift(const zz_t *u, const zz_t *v, zz_t *w)
1494
1409
  return ZZ_VAL;
1495
1410
  }
1496
1411
 
1497
- int64_t shift;
1412
+ uint64_t shift;
1498
1413
 
1499
1414
  if (zz_get(v, &shift)) {
1500
1415
  return zz_set(zz_isneg(u) ? -1 : 0, w);
1501
1416
  }
1502
- return zz_quo_2exp(u, (zz_bitcnt_t)shift, w);
1417
+ return zz_quo_2exp(u, shift, w);
1503
1418
  }
1504
1419
 
1505
1420
  BINOP_INT(lshift)
@@ -1547,17 +1462,29 @@ power(PyObject *self, PyObject *other, PyObject *module)
1547
1462
  Py_DECREF(vf);
1548
1463
  return resf;
1549
1464
  }
1550
- res = MPZ_new();
1551
1465
 
1552
- int64_t exp;
1466
+ uint64_t exp;
1553
1467
 
1554
- if (!res || zz_get(&v->z, &exp)
1555
- || zz_pow(&u->z, (zz_digit_t)exp, &res->z))
1556
- {
1557
- /* LCOV_EXCL_START */
1558
- Py_CLEAR(res);
1559
- PyErr_SetNone(PyExc_MemoryError);
1560
- /* LCOV_EXCL_STOP */
1468
+ if (zz_get(&v->z, &exp)) {
1469
+ PyErr_SetString(PyExc_OverflowError,
1470
+ "too many digits in integer");
1471
+ }
1472
+ else {
1473
+ res = MPZ_new();
1474
+ if (res) {
1475
+ zz_err ret = zz_pow(&u->z, exp, &res->z);
1476
+
1477
+ if (ret) {
1478
+ Py_CLEAR(res);
1479
+ if (ret == ZZ_MEM) {
1480
+ PyErr_SetNone(PyExc_MemoryError); /* LCOV_EXCL_LINE */
1481
+ }
1482
+ else {
1483
+ PyErr_SetString(PyExc_OverflowError,
1484
+ "too many digits in integer");
1485
+ }
1486
+ }
1487
+ }
1561
1488
  }
1562
1489
  Py_DECREF(u);
1563
1490
  Py_DECREF(v);
@@ -1871,58 +1798,67 @@ noop:
1871
1798
  }
1872
1799
 
1873
1800
  MPZ_Object *ndigits = NULL;
1874
- zz_t exp, ten, p;
1875
-
1876
- CHECK_OP_INT(ndigits, args[0]);
1877
1801
 
1878
- if (zz_isneg(&ndigits->z)) {
1879
- if (zz_init(&exp) || zz_pos(&ndigits->z, &exp)) {
1880
- /* LCOV_EXCL_START */
1881
- zz_clear(&exp);
1882
- Py_DECREF(ndigits);
1883
- return PyErr_NoMemory();
1884
- /* LCOV_EXCL_STOP */
1885
- }
1802
+ if (MPZ_Check(args[0])) {
1803
+ ndigits = (MPZ_Object *)plus(args[0]);
1886
1804
  }
1887
1805
  else {
1806
+ ndigits = MPZ_from_int(args[0]);
1807
+ }
1808
+ if (!ndigits) {
1809
+ return NULL;
1810
+ }
1811
+ if (!zz_isneg(&ndigits->z)) {
1888
1812
  Py_DECREF(ndigits);
1889
1813
  goto noop;
1890
1814
  }
1891
- Py_DECREF(ndigits);
1892
- if (zz_init(&ten) || zz_set(10, &ten) || exp.size != 1) {
1815
+
1816
+ zz_t divisor;
1817
+ uint64_t exp;
1818
+
1819
+ (void)zz_neg(&ndigits->z, &ndigits->z);
1820
+ if (zz_init(&divisor) || zz_set(10, &divisor)) {
1893
1821
  /* LCOV_EXCL_START */
1894
- zz_clear(&exp);
1895
- zz_clear(&ten);
1822
+ zz_clear(&divisor);
1896
1823
  return PyErr_NoMemory();
1897
1824
  /* LCOV_EXCL_STOP */
1898
1825
  }
1899
- if (zz_init(&p) || zz_pow(&ten, exp.digits[0], &p)) {
1900
- /* LCOV_EXCL_START */
1901
- zz_clear(&exp);
1902
- zz_clear(&ten);
1903
- zz_clear(&p);
1904
- return PyErr_NoMemory();
1905
- /* LCOV_EXCL_STOP */
1826
+ if (zz_get(&ndigits->z, &exp)) {
1827
+ zz_clear(&divisor);
1828
+ goto overflow;
1906
1829
  }
1907
- zz_clear(&exp);
1908
- zz_clear(&ten);
1830
+
1831
+ zz_err ret = zz_pow(&divisor, exp, &divisor);
1832
+
1833
+ if (ret) {
1834
+ zz_clear(&divisor);
1835
+ Py_DECREF(ndigits);
1836
+ if (ret == ZZ_MEM) {
1837
+ return PyErr_NoMemory(); /* LCOV_EXCL_LINE */
1838
+ }
1839
+ overflow:
1840
+ PyErr_SetString(PyExc_OverflowError,
1841
+ "too many digits in integer");
1842
+ return NULL;
1843
+ }
1844
+ Py_DECREF(ndigits);
1909
1845
 
1910
1846
  MPZ_Object *res = MPZ_new();
1911
1847
 
1912
1848
  if (!res) {
1913
1849
  /* LCOV_EXCL_START */
1914
- zz_clear(&p);
1850
+ zz_clear(&divisor);
1915
1851
  return NULL;
1916
1852
  /* LCOV_EXCL_STOP */
1917
1853
  }
1918
- if (zz_divnear(&u->z, &p, NULL, &res->z)) {
1854
+ if (zz_divnear(&u->z, &divisor, NULL, &res->z)) {
1919
1855
  /* LCOV_EXCL_START */
1920
- zz_clear(&p);
1856
+ zz_clear(&divisor);
1921
1857
  Py_DECREF(res);
1922
1858
  return PyErr_NoMemory();
1923
1859
  /* LCOV_EXCL_STOP */
1924
1860
  }
1925
- zz_clear(&p);
1861
+ zz_clear(&divisor);
1926
1862
  if (zz_sub(&u->z, &res->z, &res->z)) {
1927
1863
  /* LCOV_EXCL_START */
1928
1864
  Py_DECREF(res);
@@ -1930,8 +1866,6 @@ noop:
1930
1866
  /* LCOV_EXCL_STOP */
1931
1867
  }
1932
1868
  return (PyObject *)res;
1933
- end:
1934
- return NULL;
1935
1869
  }
1936
1870
 
1937
1871
  static PyObject *
@@ -1950,8 +1884,8 @@ __sizeof__(PyObject *self, PyObject *Py_UNUSED(ignored))
1950
1884
  {
1951
1885
  MPZ_Object *u = (MPZ_Object *)self;
1952
1886
 
1953
- return PyLong_FromSize_t(sizeof(MPZ_Object)
1954
- + (unsigned int)(u->z).alloc*sizeof(zz_digit_t));
1887
+ return PyLong_FromSize_t(sizeof(MPZ_Object) - sizeof(zz_t)
1888
+ + zz_sizeof(&u->z));
1955
1889
  }
1956
1890
 
1957
1891
  static PyObject *
@@ -2186,10 +2120,18 @@ gmp_lcm(PyObject *Py_UNUSED(module), PyObject *const *args, Py_ssize_t nargs)
2186
2120
  Py_DECREF(arg);
2187
2121
  continue;
2188
2122
  }
2189
- if (zz_lcm(&res->z, &arg->z, &res->z)) {
2123
+
2124
+ zz_err ret = zz_lcm(&res->z, &arg->z, &res->z);
2125
+
2126
+ if (ret) {
2190
2127
  /* LCOV_EXCL_START */
2191
2128
  Py_DECREF(res);
2192
2129
  Py_DECREF(arg);
2130
+ if (ret == ZZ_BUF) {
2131
+ PyErr_SetString(PyExc_OverflowError,
2132
+ "too many digits in integer");
2133
+ return NULL;
2134
+ }
2193
2135
  return PyErr_NoMemory();
2194
2136
  /* LCOV_EXCL_STOP */
2195
2137
  }
@@ -2221,7 +2163,7 @@ gmp_isqrt(PyObject *Py_UNUSED(module), PyObject *arg)
2221
2163
  PyErr_SetString(PyExc_ValueError,
2222
2164
  "isqrt() argument must be nonnegative");
2223
2165
  }
2224
- if (ret == ZZ_MEM) {
2166
+ else {
2225
2167
  PyErr_NoMemory(); /* LCOV_EXCL_LINE */
2226
2168
  }
2227
2169
  end:
@@ -2250,11 +2192,11 @@ gmp_isqrt_rem(PyObject *Py_UNUSED(module), PyObject *arg)
2250
2192
  if (ret == ZZ_OK) {
2251
2193
  tup = PyTuple_Pack(2, root, rem);
2252
2194
  }
2253
- if (ret == ZZ_VAL) {
2195
+ else if (ret == ZZ_VAL) {
2254
2196
  PyErr_SetString(PyExc_ValueError,
2255
2197
  "isqrt() argument must be nonnegative");
2256
2198
  }
2257
- if (ret == ZZ_MEM) {
2199
+ else {
2258
2200
  PyErr_NoMemory(); /* LCOV_EXCL_LINE */
2259
2201
  }
2260
2202
  end:
@@ -2278,17 +2220,24 @@ gmp_fac(PyObject *Py_UNUSED(module), PyObject *arg)
2278
2220
  goto err;
2279
2221
  }
2280
2222
 
2281
- int64_t n;
2223
+ uint64_t n;
2282
2224
 
2283
- if (zz_get(&x->z, &n) || n > LONG_MAX) {
2225
+ if (zz_get(&x->z, &n)) {
2226
+ overflow:
2284
2227
  PyErr_Format(PyExc_OverflowError,
2285
2228
  "fac() argument should not exceed %ld",
2286
- LONG_MAX);
2229
+ ULONG_MAX);
2287
2230
  goto err;
2288
2231
  }
2289
2232
  Py_XDECREF((PyObject *)x);
2290
- if (zz_fac((zz_digit_t)n, &res->z)) {
2233
+
2234
+ zz_err ret = zz_fac((zz_digit_t)n, &res->z);
2235
+
2236
+ if (ret) {
2291
2237
  /* LCOV_EXCL_START */
2238
+ if (ret == ZZ_BUF) {
2239
+ goto overflow;
2240
+ }
2292
2241
  PyErr_NoMemory();
2293
2242
  goto err;
2294
2243
  /* LCOV_EXCL_STOP */
@@ -2321,11 +2270,10 @@ gmp_comb(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
2321
2270
  goto err;
2322
2271
  }
2323
2272
 
2324
- int64_t n, k;
2273
+ uint64_t n, k;
2325
2274
 
2326
- if ((zz_get(&x->z, &n) || n > ULONG_MAX)
2327
- || (zz_get(&y->z, &k) || k > ULONG_MAX))
2328
- {
2275
+ if (zz_get(&x->z, &n) || zz_get(&y->z, &k)) {
2276
+ overflow:
2329
2277
  PyErr_Format(PyExc_OverflowError,
2330
2278
  "comb() arguments should not exceed %ld",
2331
2279
  ULONG_MAX);
@@ -2333,8 +2281,14 @@ gmp_comb(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
2333
2281
  }
2334
2282
  Py_XDECREF((PyObject *)x);
2335
2283
  Py_XDECREF((PyObject *)y);
2336
- if (zz_bin((zz_digit_t)n, (zz_digit_t)k, &res->z)) {
2284
+
2285
+ zz_err ret = zz_bin(n, k, &res->z);
2286
+
2287
+ if (ret) {
2337
2288
  /* LCOV_EXCL_START */
2289
+ if (ret == ZZ_BUF) {
2290
+ goto overflow;
2291
+ }
2338
2292
  PyErr_NoMemory();
2339
2293
  goto err;
2340
2294
  /* LCOV_EXCL_STOP */
@@ -2370,11 +2324,10 @@ gmp_perm(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
2370
2324
  goto err;
2371
2325
  }
2372
2326
 
2373
- int64_t n, k;
2327
+ uint64_t n, k;
2374
2328
 
2375
- if ((zz_get(&x->z, &n) || n > ULONG_MAX)
2376
- || (zz_get(&y->z, &k) || k > ULONG_MAX))
2377
- {
2329
+ if (zz_get(&x->z, &n) || zz_get(&y->z, &k)) {
2330
+ overflow:
2378
2331
  PyErr_Format(PyExc_OverflowError,
2379
2332
  "perm() arguments should not exceed %ld",
2380
2333
  ULONG_MAX);
@@ -2394,12 +2347,17 @@ gmp_perm(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
2394
2347
  goto err;
2395
2348
  /* LCOV_EXCL_STOP */
2396
2349
  }
2397
- if (zz_fac((zz_digit_t)n, &res->z)
2398
- || zz_fac((zz_digit_t)(n-k), &den->z)
2350
+
2351
+ zz_err ret = zz_fac((zz_digit_t)n, &res->z);
2352
+
2353
+ if (ret || zz_fac((zz_digit_t)(n-k), &den->z)
2399
2354
  || zz_div(&res->z, &den->z, &res->z, NULL))
2400
2355
  {
2401
2356
  /* LCOV_EXCL_START */
2402
2357
  Py_DECREF(den);
2358
+ if (ret == ZZ_BUF) {
2359
+ goto overflow;
2360
+ }
2403
2361
  PyErr_NoMemory();
2404
2362
  goto err;
2405
2363
  /* LCOV_EXCL_STOP */
@@ -2507,14 +2465,12 @@ do_rnd:
2507
2465
  }
2508
2466
 
2509
2467
  zz_t tmp;
2468
+ zz_err ret = ZZ_OK;
2510
2469
 
2511
- if (zz_init(&tmp) || shift > INT64_MAX
2512
- || zz_set((int64_t)shift, &tmp)
2513
- || zz_add(exp, &tmp, exp))
2514
- {
2470
+ if (zz_init(&tmp) || (ret = zz_add(exp, shift, exp))) {
2515
2471
  /* LCOV_EXCL_START */
2516
2472
  zz_clear(&tmp);
2517
- return ZZ_MEM;
2473
+ return ret;
2518
2474
  /* LCOV_EXCL_STOP */
2519
2475
  }
2520
2476
  zz_clear(&tmp);
@@ -2531,14 +2487,12 @@ do_rnd:
2531
2487
  }
2532
2488
 
2533
2489
  zz_t tmp;
2490
+ zz_err ret = ZZ_OK;
2534
2491
 
2535
- if (zz_init(&tmp) || zbits > INT64_MAX
2536
- || zz_set((int64_t)zbits, &tmp)
2537
- || zz_add(exp, &tmp, exp))
2538
- {
2492
+ if (zz_init(&tmp) || (ret = zz_add(exp, zbits, exp))) {
2539
2493
  /* LCOV_EXCL_START */
2540
2494
  zz_clear(&tmp);
2541
- return ZZ_MEM;
2495
+ return ret;
2542
2496
  /* LCOV_EXCL_STOP */
2543
2497
  }
2544
2498
  zz_clear(&tmp);
@@ -2549,6 +2503,7 @@ do_rnd:
2549
2503
  }
2550
2504
  return ZZ_OK;
2551
2505
  }
2506
+
2552
2507
  static PyObject *
2553
2508
  gmp__mpmath_normalize(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
2554
2509
  {
@@ -2578,13 +2533,19 @@ gmp__mpmath_normalize(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
2578
2533
 
2579
2534
  MPZ_Object *man = (MPZ_Object *)plus(args[1]);
2580
2535
  MPZ_Object *exp = MPZ_from_int(args[2]);
2536
+ zz_err ret = ZZ_OK;
2581
2537
 
2582
- if (!exp || !man || zz_mpmath_normalize(prec, rnd, &negative,
2583
- &man->z, &exp->z, &bc))
2538
+ if (!exp || !man || (ret = zz_mpmath_normalize(prec, rnd, &negative,
2539
+ &man->z, &exp->z, &bc)))
2584
2540
  {
2585
2541
  /* LCOV_EXCL_START */
2586
2542
  Py_XDECREF((PyObject *)man);
2587
2543
  Py_XDECREF((PyObject *)exp);
2544
+ if (ret == ZZ_BUF) {
2545
+ PyErr_SetString(PyExc_OverflowError,
2546
+ "too many digits in integer");
2547
+ return NULL;
2548
+ }
2588
2549
  return PyErr_NoMemory();
2589
2550
  /* LCOV_EXCL_STOP */
2590
2551
  }
@@ -2661,13 +2622,19 @@ gmp__mpmath_create(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
2661
2622
  }
2662
2623
 
2663
2624
  MPZ_Object *exp = MPZ_from_int(args[1]);
2625
+ zz_err ret = ZZ_OK;
2664
2626
 
2665
- if (!exp || zz_mpmath_normalize(prec, rnd, &negative,
2666
- &man->z, &exp->z, &bc))
2627
+ if (!exp || (ret = zz_mpmath_normalize(prec, rnd, &negative,
2628
+ &man->z, &exp->z, &bc)))
2667
2629
  {
2668
2630
  /* LCOV_EXCL_START */
2669
2631
  Py_DECREF(man);
2670
2632
  Py_XDECREF((PyObject *)exp);
2633
+ if (ret == ZZ_BUF) {
2634
+ PyErr_SetString(PyExc_OverflowError,
2635
+ "too many digits in integer");
2636
+ return NULL;
2637
+ }
2671
2638
  return PyErr_NoMemory();
2672
2639
  /* LCOV_EXCL_STOP */
2673
2640
  }
@@ -53,7 +53,7 @@ make --silent all install
53
53
 
54
54
  cd ..
55
55
 
56
- ZZ_VERSION=0.8.0
56
+ ZZ_VERSION=0.9.0a4
57
57
  ZZ_DIR=zz-${ZZ_VERSION}
58
58
  ZZ_URL=https://github.com/diofant/zz/releases/download/v${ZZ_VERSION}/${ZZ_DIR}.tar.gz
59
59
 
@@ -5,7 +5,7 @@ def pytest_configure(config):
5
5
  from hypothesis import settings
6
6
 
7
7
  default = settings.get_profile("default")
8
- settings.register_profile("default", settings(default, deadline=1600))
8
+ settings.register_profile("default", settings(default, deadline=3000))
9
9
  ci = settings.get_profile("ci")
10
10
  if platform.python_implementation() != "GraalVM":
11
11
  ci = settings(ci, max_examples=10000)
@@ -720,22 +720,23 @@ def test_power_errors():
720
720
  pow(object(), mpz(321))
721
721
  if platform.python_implementation() == "GraalVM":
722
722
  return # issue oracle/graalpython#551
723
+ with pytest.raises(OverflowError):
724
+ pow(mpz(2), mpz(1<<64))
723
725
  if BITCNT_MAX < (1<<64) - 1:
724
- with pytest.raises(MemoryError):
726
+ with pytest.raises(OverflowError):
725
727
  pow(mpz(1<<64), (1<<31) - 1)
726
- with pytest.raises(MemoryError):
728
+ with pytest.raises(OverflowError):
727
729
  pow(mpz(1<<64), (1<<31))
730
+ with pytest.raises(OverflowError):
731
+ mpz(1) << ((1 << 63) - 1)
728
732
  else:
729
- with pytest.raises(MemoryError):
733
+ with pytest.raises(OverflowError):
730
734
  pow(mpz(1<<64), (1<<63) - 1)
731
735
  if platform.system() != "Darwin":
732
- with pytest.raises(MemoryError):
736
+ with pytest.raises(OverflowError):
733
737
  pow(mpz(1<<64), (1<<63))
734
- with pytest.raises(OverflowError):
735
- mpz(1) << ((1 << 64) - 1)
736
- if platform.system() != "Darwin":
737
- with pytest.raises(MemoryError):
738
- mpz(1) << ((1 << 63) - 1)
738
+ with pytest.raises(OverflowError):
739
+ mpz(1) << ((1 << 64) - 1)
739
740
 
740
741
 
741
742
  @given(bigints(), integers(max_value=12345))
@@ -981,6 +982,12 @@ def test_round_interface():
981
982
  x.__round__(1, 2)
982
983
  with pytest.raises(TypeError):
983
984
  x.__round__(1j)
985
+ with pytest.raises(OverflowError):
986
+ x.__round__((-1<<64) + 1)
987
+ with pytest.raises(OverflowError):
988
+ x.__round__((-1<<62))
989
+ with pytest.raises(OverflowError):
990
+ x.__round__(-1<<127)
984
991
 
985
992
 
986
993
  @pytest.mark.skipif(platform.python_implementation() == "PyPy",
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes