def gauss_circle_norm(r2, trace=False): """ Return the number of lattice points in R2 whose norm is less than or equal to r. O(sqrt(r2)) time complexity algorithm based on Jacobi's two square theorem. """ retval = 0 quotient = 0 if trace: print('=1(4) divisors') for d in range(1, sqrtInt(r2 // 4)): count = (r2 // d + 3) // 4 - (r2 // (d + 1) + 3) // 4 quotient = d if trace: print(count, quotient, '*') retval += count * quotient ub = (r2 // (quotient + 1) - 1) // 4 prev_quot = quotient for i in range(ub, -1, -1): quotient = r2 // (4 * i + 1) if quotient == prev_quot: continue if trace: print(1, quotient) retval += quotient if trace: print('=3(4) divisors') quotient = 0 for d in range(1, sqrtInt(r2 // 4)): count = (r2 // d + 1) // 4 - (r2 // (d + 1) + 1) // 4 quotient = d if trace: print(count, quotient, '*') retval -= count * quotient ub = (r2 // (quotient + 1) - 1) // 4 prev_quot = quotient for i in range(ub, -1, -1): quotient = r2 // (4 * i + 3) if quotient == prev_quot: continue if trace: print(1, quotient) retval -= quotient retval *= 4 return retval + 1 # don't forget the origin
def principal_representations(n, m): """ yield a sequence of positive (a, b) such that a**2 + n * b**2 = m """ ub = sqrtInt(m / n) ii = 0 while ii <= ub: xx = m - n * ii**2 if issq(xx): yield sqrtInt(xx), ii ii += 1
def sievecntsum(n, p=None): """ Return both the count and the sum of the numbers not excluded by a sieve of [1..n] by all primes up to and including p. """ if p is None: p = sqrtInt(n) V = [n // i for i in range(1, p + 1)] V += list(range(V[-1] - 1, 0, -1)) S0 = {i: i - 1 for i in V} S1 = {i: i * (i + 1) // 2 - 1 for i in V} SP = {i: i * (i + 1) // 2 - 1 for i in V} for p in chain([2], range(3, p + 1, 2)): if S0[p] > S0[p - 1]: # p is prime p2 = p * p for v in V: if v < p2: break vmodp = v // p D0 = S0[vmodp] - S0[p - 1] D1 = S1[vmodp] - S1[p - 1] S0[v] -= D0 S1[v] -= p * D1 SP[v] -= p * (D1 - D0) return S0[n], S1[n], SP[n]
def fundamental_unit_old(d): if d <= 1: raise ValueError('%d is not >= 2' % (d, )) b = 1 while True: if issq(b * b * d - 4): a = sqrtInt(b * b * d - 4) break if issq(b * b * d + 4): a = sqrtInt(b * b * d + 4) break b += 1 if d % 4 == 1: return QuadInt(d, (a - b) / 2, b) else: return QuadInt(d, a / 2, b / 2)
def sum_sigma1(n): r""" :param n: a positive integer :return: :math:`\displaystyle\sum_{k\in[1\dots n]} \sigma(k)` """ sqrtk = sqrtInt(n) part1 = sum(d * (n // d) for d in range(1, n // sqrtk + 1)) part2 = sum(sumrange(n // (d + 1), n // d) * d for d in range(1, sqrtk)) return part1 + part2
def sieve(n): """ Return the list of primes in [2..n] """ S = np.ones((n + 1, ), dtype=bool) S[0] = False S[1] = False p = 2 sqrtn = sqrtInt(n) while p <= sqrtn: if S[p]: S[2 * p::p] = False p += 1 return filter(lambda pp: S[pp], range(n + 1))
def _partial_totient_alternate(n, k): r""" :param n: a positive integer :return: the number of integers in [1..n] that are relatively prime to k """ if n == 0: return 0 kps = [p for (p, _) in factorize2(k)] V = [n // i for i in range(1, sqrtInt(n) + 1)] V += list(range(V[-1] - 1, -1, -1)) S1 = {i: i for i in V} for p in kps: for v in V: if v < p: break S1[v] -= S1[v // p] return S1[n]
def sievesum(n, p=None): """ Return the sum of all numbers not excluded by a sieve of [1..n] by all primes up to and including p. """ if p is None: p = sqrtInt(n) V = [n // i for i in range(1, p + 1)] V += list(range(V[-1] - 1, 0, -1)) S = {i: i * (i + 1) // 2 - 1 for i in V} for p in range(2, p + 1): if S[p] > S[p - 1]: # p is prime sp = S[p - 1] # sum of primes smaller than p p2 = p * p for v in V: if v < p2: break S[v] -= p * (S[v // p] - sp) return S[n]
def sievecnt(n, p=None): """ Return the count of numbers not excluded by a sieve of [1..n] by all primes up to and including p. If p is not given then sieve up to sqrt(n). """ if p is None: p = sqrtInt(n) V = [n // i for i in range(1, p + 1)] V += list(range(V[-1] - 1, 0, -1)) S = {i: i - 1 for i in V} for p in range(2, p + 1): if S[p] > S[p - 1]: # p is prime sp = S[p - 1] # number of primes smaller than p p2 = p * p for v in V: if v < p2: break S[v] -= (S[v // p] - sp) return S[n]
def sievecntsum(n): p = sqrtInt(n) if (p + 1)**2 <= n: p += 1 V = [n // i for i in range(1, p + 1)] V += list(range(V[-1] - 1, 0, -1)) S0 = {i: i - 1 for i in V} S1 = {i: i * (i + 1) // 2 - 1 for i in V} SP = {i: i * (i + 1) // 2 - 1 for i in V} for p in range(2, p + 1): if S0[p] > S0[p - 1]: # p is prime p2 = p * p for v in V: if v < p2: break vmodp = v // p D0 = S0[vmodp] - S0[p - 1] D1 = S1[vmodp] - S1[p - 1] S0[v] -= D0 S1[v] -= p * D1 SP[v] -= p * (D1 - D0) return S0[n], S1[n], SP[n]
def segmented_sieve(n, trace=False): """ Return the list of all prime numbers less than or equal to n. Runtime complexity of O(n) (or a bit better) with space complexity of O(sqrt(n)). """ if n <= 2: if n == 2: yield 2 return seglen = sqrtInt(n + 1) # always make seglen a multiple of 6 # add 6 so that the first segment contains sqrt(n) seglen = max(6, 6 * (seglen // 6)) + 6 wheel = [4, 2] wheel_len = len(wheel) if trace: print('segment length = %d' % (seglen, )) nsegs = (n + 1) // seglen if seglen * nsegs < n + 1: nsegs += 1 if trace: print('number of segments = %d' % (nsegs, )) ps = [2, 3] for p in ps: yield p segi = 0 seg_start = 0 seg = np.ones((seglen, ), dtype=np.int8) seg[:4] = [0, 0, 1, 1] while segi < nsegs: seg_end = seg_start + seglen - 1 if trace: print('segment number = %d' % (segi, )) print('segment start = %d' % (seg_start, )) print('segment end = %d' % (seg_end, )) ub = math.sqrt(seg_end) for p in ps: if p > ub: break zeroit(seg, (p - seg_start) % p, p) if trace: print(p, '%s' % (seg, )) starti = 1 endi = min(seglen, ub - seg_start + 1) stepi = 2 i = starti wheeli = 0 while i < endi: if seg[i]: p = seg_start + i yield p if segi == 0: ps.append(p) zeroit(seg, p * p - seg_start, p) if trace: print(p, '%s' % (seg, )) i += wheel[wheeli] # stepi wheeli = (wheeli + 1) % wheel_len maxi = min(seglen, n - seg_start + 1) while i < maxi: if seg[i]: # seq_start+i is prime p = seg_start + i yield p if segi == 0: ps.append(p) i += wheel[wheeli] wheeli = (wheeli + 1) % wheel_len segi += 1 seg_start += seglen seg[:] = 1
def bps_facts_w_rep_powerful(n, ps): """ n: the integer upper bound ps: the list of primes yields: all factorized integers [(p1, e1), ..., (pk, ek)] where p1**e1 * ... * pk**ek <= n and all pi are from the list ps Note: the implementation is iterative, and not recursive, and so is suitable for cases where ps is large (i.e. cases where the stack would normally grow to the size of ps) """ num_primes = len(ps) if n < 1: return yield [] val = [[ps[-1], num_primes - 1, 2, n // (ps[-1]**2)]] while True: yield [(v[0], v[2]) for v in val] # # find the largest prime that is # 1) as large or larger than the # primes already in the factorization, and # 2) less than what is left # pi = num_primes - 1 p = ps[pi] last_val = val[-1] last_p = last_val[0] last_pi = last_val[1] last_n = last_val[3] sqrt_last_n = sqrtInt(last_n) lb = max(last_p, sqrt_last_n) if last_p > last_n: # sqrt_last_n: pi = last_pi - 1 if pi >= 0: p = ps[pi] else: while p > lb: pi -= 1 if pi < 0: break p = ps[pi] if p == last_p and p > last_n: pi -= 1 if pi >= 0: p = ps[pi] if pi < 0: return # # if there is no such prime, we have to back # track over the previous prime used. # if p < last_p: # if there is not an add'l prime pi = last_val[1] - 1 p = ps[pi] if len(val) == 1: last_val[:] = [p, pi, 2, n // (p * p)] else: del val[-1] last_val = val[-1] if p == last_val[0]: last_val[2] += 1 last_val[3] //= p else: val.append([p, pi, 2, last_val[3] // (p * p)]) elif p == last_p: # we can divide by our prime again last_val[2] += 1 last_val[3] //= p else: val.append([p, pi, 2, last_n // (p * p)])