Performance 避免Nim中的整数溢出
我昨天开始学习Nim,并决定编写一个小测试来与Rust进行性能比较。该代码编写起来相当简单,适用于10^9以下的值。但是,我需要至少用10^12测试它,因为溢出,即使在使用uint时也会给出错误的值 我一直在尝试对大多数变量进行不同的转换,但似乎无法避免溢出。当然,任何让代码更容易阅读的建议都是非常受欢迎的Performance 避免Nim中的整数溢出,performance,overflow,performance-testing,nim-lang,Performance,Overflow,Performance Testing,Nim Lang,我昨天开始学习Nim,并决定编写一个小测试来与Rust进行性能比较。该代码编写起来相当简单,适用于10^9以下的值。但是,我需要至少用10^12测试它,因为溢出,即使在使用uint时也会给出错误的值 我一直在尝试对大多数变量进行不同的转换,但似乎无法避免溢出。当然,任何让代码更容易阅读的建议都是非常受欢迎的 import math import sequtils import unsigned proc sum_min_pfactor(N : uint) : uint = proc f
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
for i in -1..v-1:
s_cnt[i+1] = i.uint
for i in 0..v:
s_sum[i] = f(i.uint)
for i in 1..v:
l_cnt[i] = N div i.uint - 1
l_sum[i] = f(N div i.uint)
for 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 and 1) + 1
var finish = min(v,N.int div q)
for i in countup(p+interval,finish,interval):
if used[i]:
continue
var d = i * 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:
for i in countup(q,finish-1,p*interval):
used[i] = true
for i in countdown(v,q-1):
var t = i 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))))
导入数学
导入序列
导入未签名
过程和最小因子(N:uint):uint=
程序f(n:uint):uint=
返回n*(n+1)分区2-1
变量
v=int(数学sqrt(float(N)))
used=newSeqWith(v+1,false)
s_sum,s_cnt,l_cnt,l_sum=newSeq[uint](v+1)
ret=0.uint
对于i in-1..v-1:
s_cnt[i+1]=i.uint
对于0..v中的i:
s_和[i]=f(i.uint)
对于1..v中的i:
l_cnt[i]=N div i.uint-1
l_和[i]=f(N分i.uint)
对于2..v中的p:
如果s_cnt[p]==s_cnt[p-1]:
持续
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
变量区间=(p和1)+1
var finish=最小值(v,N.int div q)
对于倒计时中的i(p+间隔、结束、间隔):
如果使用[i]:
持续
var d=i*p
如果d如何解决生锈问题?Rust的Int最多也应该是64位。在f
函数中,当n
为1000000000时会有点困难。您有几个选择:
- 您可以使用浮动代替,但精度较低
- 您可以使用int128,但性能较低:
- 或者您可以使用bigint:
- (高性能,取决于GMP)
- (低性能,用Nim编写,测试不多)
一些风格变化:
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)
for i in 0..v: s_cnt[i] = i-1
for i in 1..v: s_sum[i] = f(i)
for i in 1..v: l_cnt[i] = N div i - 1
for i in 1..v: l_sum[i] = f(N div i)
for 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 and 1) + 1
let finish = min(v,N div q)
for i in countup(p+interval,finish,interval):
if used[i]:
continue
let d = i * 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:
for i in countup(q,finish-1,p*interval):
used[i] = true
for i in countdown(v,q-1):
let t = i div p
s_cnt[i] -= s_cnt[t] - p_cnt
s_sum[i] -= (s_sum[t] - p_sum) * p
result += l_sum[1]
for i in 2..12:
echo sum_min_pfactor(int(math.pow(10,i.float)))
导入数学
过程和最小因子(N:int):int=
程序f(n:int):int=
n*(n+1)分区2-1
变量
v=math.sqrt(N.float).int
s_cnt,s_sum,l_cnt,l_sum=newSeq[int](v+1)
used=newSeq[bool](v+1)
对于0..v:s_cnt[i]=i-1中的i
对于1..v:s_和[i]=f(i)
对于1..v:l_cnt[i]=N div i-1中的i
对于1..v:l_sum[i]=f(N div i)
对于2..v中的p:
如果s_cnt[p]==s_cnt[p-1]:
持续
让
p_cnt=s_cnt[p-1]
p_sum=s_sum[p-1]
q=p*p
结果+=p*(l_cnt[p]-p_cnt)
l_cnt[1]=l_cnt[p]-p_cnt
l_和[1]-=(l_和[p]-p_和)*p
设区间=(p和1)+1
让完工=最小(v,N div q)
对于倒计时中的i(p+间隔、结束、间隔):
如果使用[i]:
持续
设d=i*p
如果d请同时查看bignum包:
它是nim gmp的高级包装器,因此您不必处理诸如不同编程模型之类的低级内容(gmp广泛使用长C类型,因此在针对Win64-LLP64时有点麻烦)。我还没有在Rust中启动解决方案,我决定先从nim开始。经过一些努力,我实际上在代码中成功地使用了uint,但事实上,它还没有达到我需要的范围,这令人沮丧。所以这两种语言都不支持大整数/128位整数?我添加了一些建议,包括大整数和128位整数。但是你的表现会受到很大的影响。128位ints或GMP可能很好用。很好,正是我需要的!我将看一看128位ints实现,它从来没有处理过GMP,但是如果差异很大,我可能会使用大整数模块。