i started learning nim yesterday , decided code little test make performance comparison rust. code easy write , works values 10^9. however, need test @ least 10^12, gives incorrect values because of overflow, while using uint.
i've been trying different conversions variables can't seem avoid overflow. of course, suggestions make code easier read more welcome!
import math import sequtils import unsigned proc sum_min_pfactor(n : uint) : uint = proc f(n : uint) : uint = return n*(n+1) div 2 - 1 var v = int(math.sqrt(float(n))) used = newseqwith(v+1,false) s_sum,s_cnt,l_cnt,l_sum = newseq[uint](v+1) ret = 0.uint in -1..v-1: s_cnt[i+1] = i.uint in 0..v: s_sum[i] = f(i.uint) in 1..v: l_cnt[i] = n div i.uint - 1 l_sum[i] = f(n div i.uint) p in 2..v: if s_cnt[p] == s_cnt[p-1]: continue var p_cnt = s_cnt[p - 1] var p_sum = s_sum[p - 1] var q = p * p ret += p.uint * (l_cnt[p] - p_cnt) l_cnt[1] -= l_cnt[p] - p_cnt l_sum[1] -= (l_sum[p] - p_sum) * p.uint var interval = (p , 1) + 1 var finish = min(v,n.int div q) in countup(p+interval,finish,interval): if used[i]: continue var d = * p if d <= v: l_cnt[i] -= l_cnt[d] - p_cnt l_sum[i] -= (l_sum[d] - p_sum) * p.uint else: var t = n.int div d l_cnt[i] -= s_cnt[t] - p_cnt l_sum[i] -= (s_sum[t] - p_sum) * p.uint if q <= v: in countup(q,finish-1,p*interval): used[i] = true in countdown(v,q-1): var t = div p s_cnt[i] -= s_cnt[t] - p_cnt s_sum[i] -= (s_sum[t] - p_sum) * p.uint return l_sum[1] + ret echo(sum_min_pfactor(uint(math.pow(10,2))))
how solve in rust? rust's ints should 64bit @ most. in f function gets bit difficult when n 10000000000. have few choices:
- you use floats instead, have lower precision
- you use int128, lower performance: https://bitbucket.org/behrends/nimlongint/src
- or use bigints:
- https://github.com/fedeomoto/nim-gmp (high performance, depends on gmp)
- https://github.com/def-/nim-bigints (low performance, written in nim, not tested much)
some stylistic changes:
import math proc sum_min_pfactor(n: int): int = proc f(n: int): int = n*(n+1) div 2 - 1 var v = math.sqrt(n.float).int s_cnt, s_sum, l_cnt, l_sum = newseq[int](v+1) used = newseq[bool](v+1) in 0..v: s_cnt[i] = i-1 in 1..v: s_sum[i] = f(i) in 1..v: l_cnt[i] = n div - 1 in 1..v: l_sum[i] = f(n div i) p in 2..v: if s_cnt[p] == s_cnt[p-1]: continue let p_cnt = s_cnt[p - 1] p_sum = s_sum[p - 1] q = p * p result += p * (l_cnt[p] - p_cnt) l_cnt[1] -= l_cnt[p] - p_cnt l_sum[1] -= (l_sum[p] - p_sum) * p let interval = (p , 1) + 1 let finish = min(v,n div q) in countup(p+interval,finish,interval): if used[i]: continue let d = * p if d <= v: l_cnt[i] -= l_cnt[d] - p_cnt l_sum[i] -= (l_sum[d] - p_sum) * p else: let t = n div d l_cnt[i] -= s_cnt[t] - p_cnt l_sum[i] -= (s_sum[t] - p_sum) * p if q <= v: in countup(q,finish-1,p*interval): used[i] = true in countdown(v,q-1): let t = div p s_cnt[i] -= s_cnt[t] - p_cnt s_sum[i] -= (s_sum[t] - p_sum) * p result += l_sum[1] in 2..12: echo sum_min_pfactor(int(math.pow(10,i.float)))
Comments
Post a Comment