- 注册时间
- 2020-11-9
- 最后登录
- 1970-1-1
- 威望
- 星
- 金币
- 枚
- 贡献
- 分
- 经验
- 点
- 鲜花
- 朵
- 魅力
- 点
- 上传
- 次
- 下载
- 次
- 积分
- 3828
- 在线时间
- 小时
|
发表于 2021-2-3 09:12:25
|
显示全部楼层
本帖最后由 uk702 于 2021-2-3 10:00 编辑
julia 的参考代码如下,主要思路如下:
1)在 10^5 内及每找到一个候选者只作校准,也就是指定新的偏差值 θ(代码中是变量 delta )
2)按照新的 偏差值 θ,查找候选者表,如果这时 θ 对应的候选者表还没有建立,则建立之,
否则,直接从候选者表获取候选者,再对该候选者计算偏差,如果偏差极小,则这个候选者就是所需的解
否则,重新在 θ (这时 θ 是一个新值)表中查找下一个候选者。
3)若 n 离当初建立 θ 表的时候已经偏离超过 10^10,原 θ 表应当视作老化,应当重新建立 θ 表。
(这一步 julia 代码没有实现)
这里的 θ 相当 于 #133楼的 c11, c21, c31,代码中的 dt 相当于 #133楼的 c12,c22, c32,...,
但由于 c12,c22, c32 在 10^10 内几乎不变(偏差小于 10^-5),因此,这个参数只用于计算候选者,θ 表认为与之独立。
#现假设分多段来逼近,这样,我们首先选取 s1,使得 (log(u1)/log(10))*s1 接近一个整数
#但实际上肯定不会等于整数,这时有一个偏差 θ
#下一步假设偏差是 θ,u2=u1+s1,x=log(u2)/log(10),这相当于求解 qx=p-θ
#若将 x 视作常数,可以考虑将 qx+θ 最接近整数的 q 制作成一张 [θ, q] 的表。
# θ 本身误差导致的偏差,公式表明 qx+θ 的偏差只取决于 θ 本身的分辨率,
#因此,取 θ 为 10^-5 的精度就足够了
- lgpi=log(big(pi));lg10=log(big(10.));
- h(n) = (n=big(n);log(sqrt(2.0*pi*n)) + n*log(n)) - n * (1-1/(0.4+12*n^2));
- diff(n) = (n=big(n);delta = h(n) - lgpi; d10f = delta/lg10; d10i = round(BigInt, d10f); d10f-d10i);
- M=10^5; N=M; ps=big(0.0002); nt = zeros(Int64, M*10);
- function getnext(n, delta, dt, dd)
- id = rem(floor(Int, delta*M), M, RoundDown);
- # 偏差为 θ 的表已经建立,直接使用
- if nt[id*10+1] != 0
- return nt[id*10+1:id*10+10]
- end
- # 为 θ 建立候选者表
- i = 0; j = 1; dta = big(0.0);
- while true
- delta += dt
- dt += dd
- i += 1
- dta = delta - round(BigInt, delta)
- #println("delta = $delta, dta = $dta, abs(dta) < ps = $(abs(dta) < ps)")
- if abs(dta) < ps || i > N
- nt[id*10+j] = i
- j = j+1
- if j>10 || i > N
- nt[id*10+10] = i
- break
- end
- end
- end
- return nt[id*10+1:id*10+10]
- end
- let n=big(119027672349942); i = 0; dta = big(0.0); mindiff = big(100.0)
- while true
- delta = diff(n); absdt = abs(delta);
- # println("test $(n), est. = $dta, real = $delta")
- if absdt < 10^-8
- println((n, absdt))
- end
- if absdt < mindiff
- mindiff = absdt
- end
- #如果 delta\dt1\dt2 被约成 0 了,下面的计算就没有意义了
- #当 n 充分大时,二次差分的累积应该相当小了,
- #如果我们将步长限制在一个合理的范围,应该可以不考虑二次差分的影响
- dt1=(h(n+1)-h(n))/lg10
- dt2=(h(n+2)-h(n+1))/lg10
- dd = dt2-dt1
- #println((dt1, dt2, dd))
- ds = getnext(n, delta, dt1, dd)
- for k=1:10
- if ds[k] > 0
- delta = diff(n+ds[k]); absdt = abs(delta);
- if absdt < 10^-8
- println((n+ds[k], absdt))
- end
- if absdt < mindiff
- mindiff = absdt
- end
- end
- end
- n += ds[10]
- end
- end
- println("use time = $(time()-t1)")
复制代码 |
|