找回密码
 欢迎注册
楼主: uk702

[擂台] 求 n 使得 n! 以 2021 开头

[复制链接]
发表于 2021-1-28 09:18:08 | 显示全部楼层
mathe的这个公式是LogGamma[n+1]函数的在无穷远处的无限逼近
$LogGamma[n+1] =\frac{\log(2\pi n)}2+n\log(n)-n+\frac1{12n}  -\frac{1}{360 n^3}+\frac{1}{1260 n^5}-\frac{1}{1680 n^7}+\frac{1}{1188 n^9}+O\left(\left(\frac{1}{n}\right)^{11}\right)$
要能同级别pk,只能搬出拉马努金了
$LogGamma[n+1] =-n+n \log (n)+\frac{1}{6} \log (n (4 n (2 n+1)+1))+\frac{\log (\pi )}{2} +\frac{1}{1440 n^3}-\frac{1}{768 n^4}+\frac{17}{16128 n^5}-\frac{19}{30720 n^7}+\frac{1}{98304 n^8}+\frac{4085}{4866048 n^9}+O\left(\left(\frac{1}{n}\right)^{11}\right)$
哦,其实Wikipedia上更丰富。
https://en.wikipedia.org/wiki/Stirling%27s_approximation
70abbc9761518df503553faca29aac924e88cdb4.jpg

评分

参与人数 1威望 +2 金币 +2 贡献 +2 经验 +2 鲜花 +2 收起 理由
uk702 + 2 + 2 + 2 + 2 + 2 赞一个!

查看全部评分

毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2021-1-28 11:01:31 | 显示全部楼层
本帖最后由 uk702 于 2021-1-28 11:03 编辑

我的高精度多核心版本,在 95s 完成 10^8 计算。
find 21440 sols, use time = 95.08599996566772


  1. # set JULIA_NUM_THREADS=8

  2. using Base.Threads

  3. t1=time();
  4. n=10^8; seg = 10000; ns=Int64(n/seg); u = log(big(2021.)); v = log(big(2022.)); w = log(big(10.0));

  5. mylock = ReentrantLock()
  6. result = Channel{Int64}(ns)
  7. sols = Int64[]

  8. function check(g)
  9.   global sols, mylock
  10.   g = g*seg
  11.   for n=g+2:g+seg+1
  12.     h = log(sqrt(2.0*pi*n)) + big(n)*log(n) - big(n)*(1-1/(0.4+12*n^2));
  13.     #h = log(sqrt(big(2.)*pi*n)) + log(n)*n - n + log(big(1.0)+1/(12*n)+1/(288*n^2)-139/(51840*n^3)-571/(2488320*n^4))
  14.     a = (h - u)/w; t = floor(Int, a);

  15.     if h < v + t*w
  16.       lock(mylock)
  17.       sols=append!(sols, n)
  18.       l = length(sols)
  19.       if l % 1000 == 0 println("find $l sols ...") end
  20.       unlock(mylock)
  21.     end
  22.   end
  23.   put!(result, g)
  24. end

  25. @threads for i=0:ns-1
  26.     check(i)
  27. end

  28. ct = 0; t = ns;
  29. while t > 1
  30.    take!(result)
  31.    global t = t - 1
  32. end

  33. for x in sols
  34.   println(x)
  35.   global ct += 1
  36. end

  37. println("find $ct sols, use time = $(time() - t1)")
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2021-1-28 16:47:20 | 显示全部楼层
本帖最后由 uk702 于 2021-1-28 16:50 编辑
uk702 发表于 2021-1-28 11:01
我的高精度多核心版本,在 95s 完成 10^8 计算。
find 21440 sols, use time = 95.08599996566772


采用两个精度,先是 double 精度进行粗算,再对临界值进行精算,将用时降到 10s 左右。
find 21440 sols, use time = 10.601999998092651


  1. # set JULIA_NUM_THREADS=8
  2. using Base.Threads

  3. t1=time();
  4. n=10^8; seg = 10000; ns=Int64(n/seg); u = log(2021.); v = log(2022.); w = log(10.0); c1=log(sqrt(2.0*pi))

  5. mylock = ReentrantLock()
  6. result = Channel{Int64}(ns)
  7. sols = Int64[]

  8. function check(g)
  9.   global sols, mylock
  10.   g = g*seg
  11.   for n=g+2:g+seg+1
  12.     h = c1 + log(n)*(n+0.5) - n;
  13.     a = (h - u)/w; t = floor(Int, a);

  14.     eps = v + t*w - h
  15.     if eps > 0
  16.       if eps > 0.001
  17.         lock(mylock)
  18.         sols=append!(sols, n)
  19.         unlock(mylock)
  20.       else
  21.         h = c1 + log(n)*(big(n)+0.5) - big(n); a = (h - log(big(2021.)))/log(big(10.0)); t = floor(Int, a);
  22.         if h < v + t*log(big(10.0))
  23.           lock(mylock)
  24.           sols=append!(sols, n)
  25.           unlock(mylock)
  26.         end
  27.       end
  28.       
  29.       l = length(sols)
  30.       if l % 1000 == 0 println("find $l sols ...") end
  31.     end
  32.   end
  33.   put!(result, g)
  34. end

  35. @threads for i=0:ns-1
  36.     check(i)
  37. end

  38. ct = 0; t = ns;
  39. while t > 1
  40.    take!(result)
  41.    global t = t - 1
  42. end

  43. for x in sols
  44.   println(x)
  45.   global ct += 1
  46. end

  47. println("find $ct sols, use time = $(time() - t1)")
复制代码

点评

嗯,还得再删去一个才正确:80495570!=20209999800521182002129071...,  发表于 2021-1-28 20:42
多了哪个解  发表于 2021-1-28 20:13
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2021-1-28 21:38:15 | 显示全部楼层
我觉得某个帖子里我写过类似算法

https://bbs.emath.ac.cn/thread-969-1-1.html

点评

多点几次。  发表于 2021-1-29 09:37
本人点值有限,2分好像是上限了。  发表于 2021-1-29 07:27
的代码  发表于 2021-1-28 22:56

评分

参与人数 2威望 +20 金币 +20 贡献 +20 经验 +20 鲜花 +20 收起 理由
uk702 + 8 + 8 + 8 + 8 + 8 顶礼膜拜*3
wayne + 12 + 12 + 12 + 12 + 12 天啦,现在回头看你们的讨论,我还是看不懂.

查看全部评分

毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2021-1-29 08:32:51 | 显示全部楼层
uk702 发表于 2021-1-28 16:47
采用两个精度,先是 double 精度进行粗算,再对临界值进行精算,将用时降到 10s 左右。
find 21440 so ...


fix 多出一个解的 bug,16 核并行,耗时 10.6s。
find 21439 sols, use time = 10.594000101089478

  1. # set JULIA_NUM_THREADS=16
  2. using Base.Threads

  3. t1=time();
  4. n=10^8; seg = 10000; ns=Int64(n/seg); u = log(2021.); v = log(2022.); w = log(10.0); c1=log(sqrt(2.0*pi))

  5. mylock = ReentrantLock()
  6. result = Channel{Int64}(ns)
  7. sols = Int64[]

  8. function check(g)
  9.   global sols, mylock
  10.   g = g*seg
  11.   for n=g+2:g+seg+1
  12.     h = c1 + log(n)*(n+0.5) - n;
  13.     a = (h - u)/w; t = floor(Int, a);

  14.     eps = v + t*w - h
  15.     if eps > 0
  16.       if eps > 0.001
  17.         lock(mylock)
  18.         sols=append!(sols, n)
  19.         unlock(mylock)
  20.       else
  21.         h = c1 + log(big(n))*(big(n)+0.5) - big(n)*(big(1)-big(1)/(big(0.4)+big(12)*n^2));
  22.         a = (h - log(big(2021.)))/log(big(10.0)); t = floor(Int64, a);
  23.         if h < log(big(2022.)) + t*log(big(10.0))
  24.           lock(mylock)
  25.           sols=append!(sols, n)
  26.           unlock(mylock)
  27.         end
  28.       end
  29.       
  30.       l = length(sols)
  31.       if l % 1000 == 0 println("find $l sols ...") end
  32.     end
  33.   end
  34.   put!(result, g)
  35. end

  36. @threads for i=0:ns-1
  37.     check(i)
  38. end

  39. ct = 0; t = ns;
  40. while t > 1
  41.    take!(result)
  42.    global t = t - 1
  43. end

  44. for x in sols
  45.   println(x)
  46.   global ct += 1
  47. end

  48. println("find $ct sols, use time = $(time() - t1)")
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2021-1-29 08:38:03 | 显示全部楼层
这个问题其实是 一个方程求根的问题:定义$f(x)= x-\lfloor \frac{x}{\log (10)}\rfloor \log (10) $, 求方程 $\log (\frac{2021}{1000} ) <f(log \Gamma(n+1)) <\log (\frac{2022}{1000} )$的正整数根。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
您需要登录后才可以回帖 登录 | 欢迎注册

本版积分规则

小黑屋|手机版|数学研发网 ( 苏ICP备07505100号 )

GMT+8, 2024-11-21 21:25 , Processed in 0.039134 second(s), 18 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表