[pypy-commit] pypy py3.6: (Luanna): integrate new gcd algorithm into the pypy math module

2019-07-10 Thread cfbolz
Author: Carl Friedrich Bolz-Tereick 
Branch: py3.6
Changeset: r96959:aa95fe7b71b4
Date: 2019-07-10 13:46 +0200
http://bitbucket.org/pypy/pypy/changeset/aa95fe7b71b4/

Log:(Luanna): integrate new gcd algorithm into the pypy math module

diff --git a/pypy/module/math/__init__.py b/pypy/module/math/__init__.py
--- a/pypy/module/math/__init__.py
+++ b/pypy/module/math/__init__.py
@@ -5,7 +5,6 @@
 class Module(MixedModule):
 appleveldefs = {
'factorial' : 'app_math.factorial',
-   'gcd' :   'app_math.gcd',
 }
 
 interpleveldefs = {
@@ -57,5 +56,6 @@
'gamma'  : 'interp_math.gamma',
'lgamma' : 'interp_math.lgamma',
'isclose': 'interp_math.isclose',
+   'gcd': 'interp_math.gcd',
 }
 
diff --git a/pypy/module/math/app_math.py b/pypy/module/math/app_math.py
--- a/pypy/module/math/app_math.py
+++ b/pypy/module/math/app_math.py
@@ -47,10 +47,3 @@
 res, _, shift = _fac1(x)
 return res << shift
 
-def gcd(x, y):
-"""greatest common divisor of x and y"""
-x = abs(index(x))
-y = abs(index(y))
-while x > 0:
-x, y = y % x, x
-return y
diff --git a/pypy/module/math/interp_math.py b/pypy/module/math/interp_math.py
--- a/pypy/module/math/interp_math.py
+++ b/pypy/module/math/interp_math.py
@@ -484,3 +484,23 @@
diff <= math.fabs(rel_tol * a)) or
   diff <= abs_tol)
 return space.newbool(result)
+
+
+def gcd(space, w_a, w_b):
+"""greatest common divisor of a and b"""
+from rpython.rlib import rbigint
+w_a = space.abs(space.index(w_a))
+w_b = space.abs(space.index(w_b))
+try:
+a = space.int_w(w_a)
+b = space.int_w(w_b)
+g = rbigint.gcd_binary(a, b)
+return space.newint(g)
+except OperationError as e:
+if not e.match(space, space.w_OverflowError):
+raise
+
+a = space.bigint_w(w_a)
+b = space.bigint_w(w_b)
+g = a.gcd(b)
+return space.newlong_from_rbigint(g)
diff --git a/pypy/module/math/test/test_math.py 
b/pypy/module/math/test/test_math.py
--- a/pypy/module/math/test/test_math.py
+++ b/pypy/module/math/test/test_math.py
@@ -371,6 +371,8 @@
 assert math.gcd(0, -10) == 10
 assert math.gcd(0, 0) == 0
 raises(TypeError, math.gcd, 0, 0.0)
+assert math.gcd(-3**10*5**20*11**8, 2**5*3**5*7**20) == 3**5
+assert math.gcd(64, 200) == 8
 
 def test_inf_nan(self):
 import math
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy py3.6: no need to call abs twice

2019-07-10 Thread cfbolz
Author: Carl Friedrich Bolz-Tereick 
Branch: py3.6
Changeset: r96960:de29534e71f5
Date: 2019-07-10 15:11 +0200
http://bitbucket.org/pypy/pypy/changeset/de29534e71f5/

Log:no need to call abs twice

diff --git a/pypy/module/math/interp_math.py b/pypy/module/math/interp_math.py
--- a/pypy/module/math/interp_math.py
+++ b/pypy/module/math/interp_math.py
@@ -489,8 +489,8 @@
 def gcd(space, w_a, w_b):
 """greatest common divisor of a and b"""
 from rpython.rlib import rbigint
-w_a = space.abs(space.index(w_a))
-w_b = space.abs(space.index(w_b))
+w_a = space.index(w_a)
+w_b = space.index(w_b)
 try:
 a = space.int_w(w_a)
 b = space.int_w(w_b)
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy default: (Luanna, cfbolz): add rbigint.gcd to compute the greatest common divisor of two

2019-07-10 Thread cfbolz
Author: Carl Friedrich Bolz-Tereick 
Branch: 
Changeset: r96957:bf3310921e45
Date: 2019-07-10 13:38 +0200
http://bitbucket.org/pypy/pypy/changeset/bf3310921e45/

Log:(Luanna, cfbolz): add rbigint.gcd to compute the greatest common
divisor of two rbigint instances using Lehmer's algorithm:

https://bitbucket.org/pypy/pypy/issues/3031/mathgcd-much-slower-
than-cpython https://en.wikipedia.org/wiki/Lehmer's_GCD_algorithm

diff --git a/rpython/rlib/rbigint.py b/rpython/rlib/rbigint.py
--- a/rpython/rlib/rbigint.py
+++ b/rpython/rlib/rbigint.py
@@ -1423,6 +1423,12 @@
 bits = ovfcheck((i-1) * SHIFT) + msd_bits
 return bits
 
+def gcd(self, other):
+""" Compute the (always positive) greatest common divisor of self and
+other """
+return gcd_lehmer(self.abs(), other.abs())
+
+
 def __repr__(self):
 return "" % 
(self._digits,
 self.sign, self.numdigits(), 
len(self._digits),
@@ -2960,3 +2966,88 @@
 z.setdigit(pdigit, accum)
 z._normalize()
 return z
+
+
+def gcd_binary(a, b):
+if a == 0:
+return b
+
+if b == 0:
+return a
+
+a, b = abs(a), abs(b)
+
+shift = 0
+while (a | b) & 1 == 0:
+a >>= 1
+b >>= 1
+shift += 1
+
+while a & 1 == 0:
+a >>= 1
+
+while b & 1 == 0:
+b >>= 1
+
+while a != b:
+a, b = abs(a - b), min(a, b)
+while a & 1 == 0:
+a >>= 1
+
+return a << shift
+
+def lehmer_xgcd(a, b):
+s_old, s_new = 1, 0
+t_old, t_new = 0, 1
+while b >> (SHIFT >> 1):
+q, r = a // b, a % b
+
+a, b = b, r
+s_old, s_new = s_new, s_old - q * s_new
+t_old, t_new = t_new, t_old - q * t_new
+
+return s_old, t_old, s_new, t_new
+
+def gcd_lehmer(a, b):
+if a.lt(b):
+a, b = b, a
+
+while b.size > 1:
+a_ms = a.digit(a.size-1)
+
+x = 0
+while a_ms & (0xFF << SHIFT-8) == 0:
+a_ms <<= 8
+x += 8
+
+while a_ms & (1 << SHIFT-1) == 0:
+a_ms <<= 1
+x += 1
+
+a_ms |= a.digit(a.size-2) >> SHIFT-x
+
+if a.size == b.size:
+b_ms = (b.digit(b.size-1) << x) | (b.digit(b.size-2) >> SHIFT-x)
+elif a.size == b.size+1:
+b_ms = b.digit(b.size-1) >> SHIFT-x
+else:
+b_ms = 0
+
+if b_ms >> (SHIFT+1 >> 1) == 0:
+a, b = b, a.mod(b)
+continue
+
+s_old, t_old, s_new, t_new = lehmer_xgcd(a_ms, b_ms)
+
+n_a = a.int_mul(s_new).add(b.int_mul(t_new)).abs()
+b = a.int_mul(s_old).add(b.int_mul(t_old)).abs()
+a = n_a
+
+if a.lt(b):
+a, b = b, a
+
+if not b.tobool():
+return a
+
+a = a.mod(b)
+return rbigint.fromint(gcd_binary(b.toint(), a.toint()))
diff --git a/rpython/rlib/test/test_rbigint.py 
b/rpython/rlib/test/test_rbigint.py
--- a/rpython/rlib/test/test_rbigint.py
+++ b/rpython/rlib/test/test_rbigint.py
@@ -11,12 +11,13 @@
 from rpython.rlib import rbigint as lobj
 from rpython.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong, intmask
 from rpython.rlib.rbigint import (rbigint, SHIFT, MASK, KARATSUBA_CUTOFF,
-_store_digit, _mask_digit, InvalidEndiannessError, InvalidSignednessError)
+_store_digit, _mask_digit, InvalidEndiannessError, InvalidSignednessError,
+gcd_lehmer, lehmer_xgcd, gcd_binary)
 from rpython.rlib.rfloat import NAN
 from rpython.rtyper.test.test_llinterp import interpret
 from rpython.translator.c.test.test_standalone import StandaloneTests
 
-from hypothesis import given, strategies, example
+from hypothesis import given, strategies, example, settings
 
 longs = strategies.builds(
 long, strategies.integers())
@@ -836,6 +837,27 @@
 t = bigint.tobytes(len(s), byteorder=byteorder, signed=signed)
 assert s == t
 
+def test_gcd(self):
+assert gcd_binary(2*3*7**2, 2**2*7) == 2*7
+assert gcd_binary(-2*3*7**2, 2**2*7) == 2*7
+assert gcd_binary(2*3*7**2, -2**2*7) == 2*7
+assert gcd_binary(-2*3*7**2, -2**2*7) == 2*7
+assert gcd_binary(1234, 5678) == 2
+assert gcd_binary(13, 13**6) == 13
+assert gcd_binary(12, 0) == 12
+assert gcd_binary(0, 0) == 0
+
+x = rbigint.fromlong(9969216677189303386214405760200)
+y = rbigint.fromlong(16130531424904581415797907386349)
+g = x.gcd(y)
+assert g == rbigint.fromlong(1)
+
+for x in 
gen_signs([12843440367927679363613699686751681643652809878241019930204617606850071260822269719878805]):
+x = rbigint.fromlong(x)
+for y in 
gen_signs([12372280584571061381380725743231391746505148712246738812788540537514927882776203827701778968535]):
+y = rbigint.fromlong(y)
+g = x.gcd(y)
+assert g.tolong() == 
18218089570126697993340888567155155527541105
 
 

[pypy-commit] pypy py3.6: merge default

2019-07-10 Thread cfbolz
Author: Carl Friedrich Bolz-Tereick 
Branch: py3.6
Changeset: r96958:5a7ab6765acf
Date: 2019-07-10 13:38 +0200
http://bitbucket.org/pypy/pypy/changeset/5a7ab6765acf/

Log:merge default

diff --git a/rpython/jit/backend/arm/assembler.py 
b/rpython/jit/backend/arm/assembler.py
--- a/rpython/jit/backend/arm/assembler.py
+++ b/rpython/jit/backend/arm/assembler.py
@@ -532,26 +532,22 @@
 
 def gen_shadowstack_header(self, gcrootmap):
 # lr = shadow stack top addr
-# r4 = *lr
+# ip = *lr
 rst = gcrootmap.get_root_stack_top_addr()
 self.mc.gen_load_int(r.lr.value, rst)
-self.load_reg(self.mc, r.r4, r.lr)
-# *r4 = 1
-# the '1' is to benefit from the shadowstack 'is_minor' optimization
-self.mc.gen_load_int(r.ip.value, 1)
-self.store_reg(self.mc, r.ip, r.r4)
-# *(r4+WORD) = r.fp
-self.store_reg(self.mc, r.fp, r.r4, WORD)
+self.load_reg(self.mc, r.ip, r.lr)
+# *ip = r.fp
+self.store_reg(self.mc, r.fp, r.ip)
 #
-self.mc.ADD_ri(r.r4.value, r.r4.value, 2 * WORD)
-# *lr = r4 + 2 * WORD
-self.store_reg(self.mc, r.r4, r.lr)
+self.mc.ADD_ri(r.ip.value, r.ip.value, WORD)
+# *lr = ip + WORD
+self.store_reg(self.mc, r.ip, r.lr)
 
 def gen_footer_shadowstack(self, gcrootmap, mc):
 rst = gcrootmap.get_root_stack_top_addr()
 mc.gen_load_int(r.ip.value, rst)
 self.load_reg(mc, r.r4, r.ip)
-mc.SUB_ri(r.r4.value, r.r4.value, 2 * WORD)
+mc.SUB_ri(r.r4.value, r.r4.value, WORD)
 self.store_reg(mc, r.r4, r.ip)
 
 def _dump(self, ops, type='loop'):
diff --git a/rpython/jit/backend/arm/regalloc.py 
b/rpython/jit/backend/arm/regalloc.py
--- a/rpython/jit/backend/arm/regalloc.py
+++ b/rpython/jit/backend/arm/regalloc.py
@@ -373,6 +373,10 @@
 if box.type == REF and self.rm.is_still_alive(box):
 assert not noregs
 assert loc.is_core_reg()
+#val = self.cpu.all_reg_indexes[loc.value]
+# ^^^ That is the correct way to write it down, but as a
+# special case in the arm backend only, this is equivalent
+# to just the line below:
 val = loc.value
 gcmap[val // WORD // 8] |= r_uint(1) << (val % (WORD * 8))
 for box, loc in self.fm.bindings.iteritems():
diff --git a/rpython/rlib/rbigint.py b/rpython/rlib/rbigint.py
--- a/rpython/rlib/rbigint.py
+++ b/rpython/rlib/rbigint.py
@@ -1423,6 +1423,12 @@
 bits = ovfcheck((i-1) * SHIFT) + msd_bits
 return bits
 
+def gcd(self, other):
+""" Compute the (always positive) greatest common divisor of self and
+other """
+return gcd_lehmer(self.abs(), other.abs())
+
+
 def __repr__(self):
 return "" % 
(self._digits,
 self.sign, self.numdigits(), 
len(self._digits),
@@ -2960,3 +2966,88 @@
 z.setdigit(pdigit, accum)
 z._normalize()
 return z
+
+
+def gcd_binary(a, b):
+if a == 0:
+return b
+
+if b == 0:
+return a
+
+a, b = abs(a), abs(b)
+
+shift = 0
+while (a | b) & 1 == 0:
+a >>= 1
+b >>= 1
+shift += 1
+
+while a & 1 == 0:
+a >>= 1
+
+while b & 1 == 0:
+b >>= 1
+
+while a != b:
+a, b = abs(a - b), min(a, b)
+while a & 1 == 0:
+a >>= 1
+
+return a << shift
+
+def lehmer_xgcd(a, b):
+s_old, s_new = 1, 0
+t_old, t_new = 0, 1
+while b >> (SHIFT >> 1):
+q, r = a // b, a % b
+
+a, b = b, r
+s_old, s_new = s_new, s_old - q * s_new
+t_old, t_new = t_new, t_old - q * t_new
+
+return s_old, t_old, s_new, t_new
+
+def gcd_lehmer(a, b):
+if a.lt(b):
+a, b = b, a
+
+while b.size > 1:
+a_ms = a.digit(a.size-1)
+
+x = 0
+while a_ms & (0xFF << SHIFT-8) == 0:
+a_ms <<= 8
+x += 8
+
+while a_ms & (1 << SHIFT-1) == 0:
+a_ms <<= 1
+x += 1
+
+a_ms |= a.digit(a.size-2) >> SHIFT-x
+
+if a.size == b.size:
+b_ms = (b.digit(b.size-1) << x) | (b.digit(b.size-2) >> SHIFT-x)
+elif a.size == b.size+1:
+b_ms = b.digit(b.size-1) >> SHIFT-x
+else:
+b_ms = 0
+
+if b_ms >> (SHIFT+1 >> 1) == 0:
+a, b = b, a.mod(b)
+continue
+
+s_old, t_old, s_new, t_new = lehmer_xgcd(a_ms, b_ms)
+
+n_a = a.int_mul(s_new).add(b.int_mul(t_new)).abs()
+b = a.int_mul(s_old).add(b.int_mul(t_old)).abs()
+a = n_a
+
+if a.lt(b):
+a, b = b, a
+
+if not b.tobool():
+return a
+
+a = a.mod(b)
+return rbigint.fromint(gcd_binary(b.toint(), a.toint()))
diff --git a/rpython/rlib/test/test_rbigint.py 
b/rpython/rlib/test/test_rbigint.py
--- a/rpython/rli

[pypy-commit] pypy py3.6: ~1% speedup to GCD.

2019-07-10 Thread Stian Andreassen
Author: Stian Andreassen
Branch: py3.6
Changeset: r96961:ab71ab09aca2
Date: 2019-07-10 22:41 +0200
http://bitbucket.org/pypy/pypy/changeset/ab71ab09aca2/

Log:~1% speedup to GCD.

diff --git a/rpython/rlib/rbigint.py b/rpython/rlib/rbigint.py
--- a/rpython/rlib/rbigint.py
+++ b/rpython/rlib/rbigint.py
@@ -3013,7 +3013,7 @@
 a, b = b, a
 
 while b.size > 1:
-a_ms = a.digit(a.size-1)
+a_ms = a.digit(abs(a.size-1))
 
 x = 0
 while a_ms & (0xFF << SHIFT-8) == 0:
@@ -3024,12 +3024,12 @@
 a_ms <<= 1
 x += 1
 
-a_ms |= a.digit(a.size-2) >> SHIFT-x
+a_ms |= a.digit(abs(a.size-2)) >> SHIFT-x
 
 if a.size == b.size:
-b_ms = (b.digit(b.size-1) << x) | (b.digit(b.size-2) >> SHIFT-x)
+b_ms = (b.digit(abs(b.size-1)) << x) | (b.digit(abs(b.size-2)) >> 
SHIFT-x)
 elif a.size == b.size+1:
-b_ms = b.digit(b.size-1) >> SHIFT-x
+b_ms = b.digit(abs(b.size-1)) >> SHIFT-x
 else:
 b_ms = 0
 
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit