计算Pi的位数


15

这是一个有点不同的任务。从第1024个十六进制位置开始计算π的1024个十六进制数字。

正式地:您的程序应在不到1分钟的时间内完成,并产生以下输出:

25d479d8f6e8def7e3fe501ab6794c3b976ce0bd04c006bac1a94fb6409f60c45e5c9ec2196a246368fb6faf3e6c53b51339b2eb3b52ec6f6dfc511f9b30952ccc814544af5ebd09bee3d004de334afd660f2807192e4bb3c0cba85745c8740fd20b5f39b9d3fbdb5579c0bd1a60320ad6a100c6402c7279679f25fefb1fa3cc8ea5e9f8db3222f83c7516dffd616b152f501ec8ad0552ab323db5fafd23876053317b483e00df829e5c57bbca6f8ca01a87562edf1769dbd542a8f6287effc3ac6732c68c4f5573695b27b0bbca58c8e1ffa35db8f011a010fa3d98fd2183b84afcb56c2dd1d35b9a53e479b6f84565d28e49bc4bfb9790e1ddf2daa4cb7e3362fb1341cee4c6e8ef20cada36774c01d07e9efe2bf11fb495dbda4dae909198eaad8e716b93d5a0d08ed1d0afc725e08e3c5b2f8e7594b78ff6e2fbf2122b648888b812900df01c4fad5ea0688fc31cd1cff191b3a8c1ad2f2f2218be0e1777ea752dfe8b021fa1e5a0cc0fb56f74e818acf3d6ce89e299b4a84fe0fd13e0b77cc43b81d2ada8d9165fa2668095770593cc7314211a1477e6ad206577b5fa86c75442f5fb9d35cfebcdaf0c7b3e89a0d6411bd3ae1e7e4900250e2d2071b35e226800bb57b8e0af2464369bf009b91e5563911d59dfa6aa78c14389d95a537f207d5ba202e5b9c5832603766295cfa911c819684e734a41b3472dca7b14a94

长度最短的程序将获胜。您必须在运行时计算所有数字。您不必实现计算π的算法;如果您的语言已经提供了该功能,则可以使用它。


哈,应该很容易。(仍然是+1)我敢打赌,我可以在不到几秒钟的时间内执行它。
Mateen Ulhaq 2011年

@muntoo:然后呢?您的解决方案在哪里?
FUZxxl

我忘了做 :)顺便说一句,速度!=代码高尔夫球。
Mateen Ulhaq 2011年

@muntoo:我知道。但是我也认为,5天是完成这样简单任务的好时机。
FUZxxl

Answers:


13

鼠尾草,29个字符

从技术上讲这不是欺骗,因为数字是在运行时计算的。也就是说,它仍然便宜得要命。

hex(floor(pi*2^8192))[1025:]

1
绝对不作弊。
FUZxxl

11
嗯,楼pi。
面包箱

13

壳牌公司实用程序:48

curl -sL ow.ly/5u3hc|grep -Eom 1 '[a-f0-9]{1024}'

  • 所有输出在运行时“计算”。(感谢OP发布解决方案)
  • 一分钟内运行。(可能取决于您的互联网连接速度)

通常我会拒绝这种解决方案,因为它们是对规则的普遍滥用,不再有趣。但是,只是因为您如此偷偷摸摸地采用提供的参考解决方案并编写,所有输出都是在运行时“计算”的。(感谢OP发布解决方案),我给您一个
投票

高尔夫球版:curl -sL ow.ly/shKGY|grep -Po \\w{99,}(37)。在Dash中工作。Bash将需要一个额外的字节。
丹尼斯

6

Ĵ,156,140,137 127

d=:3 :'1|+/4 _2 _1 _1*+/(y&(16^-)%1 4 5 6+8*])"0 i.y+9'
,1([:}.'0123456789abcdef'{~[:|.[:<.[:(],~16*1|{.)^:8 d)"0\1024x+8*i.128

使用BBP公式。

难道不是在一分钟内运行(但是我们必须为J答案:P)

π的前104个数字的示例(运行速度很快):

,1([:}.'0123456789abcdef'{~[:|.[:<.[:(],~16*1|{.)^:8 d)"0\8*i.13x

243f6a8885a308d313198a2e03707344a4093822299f31d0082efa98ec4e6c89
452821e638d01377be5466cf34e90c6cc0ac29b7

为什么不使用#:将数字转换为十六进制?
FUZxxl 2011年

我不确定你是什么意思。#:将不会输出十六进制数字。
Eelvex 2011年

恕我直言,使用#:和重塑形状以生成十六进制数字比您当前的方法容易得多。
FUZxxl 2011年

你的意思是(... 16 #:) Pi?我认为我们没有足够的数字,因此无论如何我们都必须生成它们。
Eelvex

1
顺便说一句,我发现有一个动词hfd可以将数字转换为十六进制。
FUZxxl 2011年

5

JavaScript 536

(换行符和缩进仅用于易读性)

var d='0123456789abcdef',p='',o='',l=3e3,c=0,e='length';d=d+d;
function $(n,r){return n[e]<=r?0:d.indexOf(n[r])}
function g(a,b){for(i=0,t='',s=16;i<l;i++,t+=d[~~(s/b)],s=(s%b)*16);
for(;a--;t=_(t,t,1));return t}
function _(a,b,s){for(i=(a[e]>b[e]?a[e]:b[e])-1,r='',c=0;i>=0;r=(s?
  function(k){c=k>15;return d[k]}($(a,i)+$(b,i)+c):
  function(k){c=k<0;return d[k+16]}($(a,i)-$(b,i)-c))+r,i--);return r}
for(i=0;i<l;i++,p+='2');
for(j=1;j<l;p=_(p,(o+='0')+_(_(_(g(2,8*j+1),g(1,8*j+4)),g(0,8*j+5)),g(0,8*j+6)),1),j++);
console.log(p.slice(1024,2048))

在使用Intel i5核心的笔记本电脑上的Google Chrome 14上,大约需要25秒。别人可以打高尔夫吗?我打高尔夫球不好.. :(

以下是非高尔夫。我只是删除所有注释,然后将其更改为打高尔夫球。

不要提及for(;s>=b;s-=b);s*=16;。我将其更改为s=(s%b)*16。:P

/**
Calculate PI-3 to 3000 (3e3) digits.
a : a
b : b
c : carry
d : digits
e : length
f : get from d
g : calculate (2^a)/b.
i,j, : for looping
l : length to calculate
p : pi
r,t : return value
*/
var d='0123456789abcdef',p='',o='',l=3e3,c=0,e='length';
d=d+d;//for carring

function $(n,r){return n[e]<=r?0:d.indexOf(n[r])}
/*
Calculate (2^a)/b. Assume that 2^a < b.
*/
function g(a,b){
    for(i=0,t='',s=16;i<l;i++){t+=d[~~(s/b)];for(;s>=b;s-=b);s*=16;}
    for(;a--;t=_(t,t,1));return t}
/*
Calculate a±b. (+ when s=1, - when s=0) When calculating minus, assume that 1>b>a>0.
*/
function _(a,b,s){
    for(i=(a[e]>b[e]?a[e]:b[e])-1,r='',c=0;i>=0;
        r=(s?function(k){c=k>15;return d[k]}($(a,i)+$(b,i)+c):
            function(k){c=k<0;return d[k+16]}($(a,i)-$(b,i)-c))+r,i--);return r;
}
/*
Using BBP formula. Calc when j=0...
4/1 - 2/4 - 1/5 - 1/6 = 3.22222222.... (b16)
*/
for(i=0;i<l;i++,p+='2');
//Calc when j>0
for(j=1;j<l;p=_(p,(o+='0')+_(_(_(g(2,8*j+1),g(1,8*j+4)),g(0,8*j+5)),g(0,8*j+6)),1),j++);
console.log(p.slice(1024,2048));

编辑:删除了完全未使用的功能。(我为什么要保留它?:/)

PS。PI的前100位

243f6a8885a308d313198a2e03707344a4093822299f31d0082efa98ec4e6c89452821e638d01377be5466cf34e90c6cc0ab


@FUZxxl:非高尔夫代码不够吗?.. :(
JiminP 2011年

确实是。但是恕我直言,如果您使用代码格式而不是使用反引号语法,则外观会更好。如我所写,如果您不喜欢,请随时恢复。
FUZxxl 2011年

d='0123456789abcdef',l=3e3,p=Array(l+1).join(2),o='',c=0,e='length';d+=d;function _(a,b,s){for(i=(a[e]>b[e]?a[e]:b[e])-1,r='',c=0;i+1;r=d[Z=F(b,i,1)+c,k=F(a,i,1)+(s?Z:16-Z),c=s?k>15:k<16,k]+r,i--);return r}function F(a,b,f){if(f)f=a[e]>b?d.indexOf(a[b]):0;else{for(i=0,f='',s=16;i++<l;f+=d[~~(s/b)],s=(s%b)*16);while(a--)f=_(f,f,1)}return f}for(j=0;++j<l;p=_(p,(o+='0')+_(_(_(F(2,z=8*j+1),F(1,z+3)),F(0,z+4)),F(0,z+5)),1));console.log(p.slice(1024,2048))
彼得·泰勒

这实际上就是所有的微优化,尽管其中一些看起来很大。最大的节省来自_在支持,操作员的中间省去了两个匿名函数。最棘手的是将$和合并g到一个函数中,并带有一个可选参数来选择它们。function并且return都非常昂贵,因此一个if(f)...else和几个,1是一个合理的权衡。
彼得·泰勒

4

PHP 116114字节

<?for(;$g?$d=0|($$g=$g--/2*$d+($$g?:2)%$g*$f)/$g--:4613^printf($i++>257?'%04x':'',$e+$d/$f=4*$g=16384)^$e=$d%$f;);

该解决方案可计算所有pi,最多2048个十六进制数字,一次计算四个十六进制数字,并输出它们的后半部分。执行时间少于5秒。用于计算的公式如下:

pi = 2 + 1/3*(2 + 2/5*(2 + 3/7*(2 + 4/9*(2 + 5/11*(2 + 6/13*(2 + 7/15*(2 + ... )))))))

获得的精度可以将余数存储在一个数组中,并递增地连续进行2 ^ 14个除法。

Python 64字节

x=p=16385
while~-p:x=p/2*x/p+2*2**8192;p-=2
print('%x'%x)[1025:]

与上述相同的方法。运行约0.2秒。

或以73字节的单线形式

print('%x'%reduce(lambda x,p:p/2*x/p+2*2**8192,range(16387,1,-2)))[1025:]

3

PARI / GP-2.4、141

forstep(d=1024,2047,8,y=frac(apply(x->sum(k=0,d+30,16^(d-k)/(8*k+x)),[1,4,5,6])*[4,-2,-1,-1]~);for(i=0,7,y=16*frac(y);printf("%X",floor(y))))

使用Bailey–Borwein–Plouffe公式(当然)。

一分钟内即可顺利运行。


3

C代码:

long ki,k,e,d=1024;
int  dig,tD=0,c,Co=0,j,js[4]  ={1,4,5,6};
double res=0.0,tres=0.0,gT,ans[4] ={0.0};
while(tD < 1024)
{while(Co<4){ j= js[Co],gT=0.0,ki= 0;
 for(; ki < d+1;ki++){ k = 8*ki+j,e= d-ki,c=1; while(e--) c = 16*c % k; gT+=((double)(c)/(double)k);}
 ans[Co] = (gT - (int)gT),++Co;}
 double gA = 4*ans[0]-2*ans[1]-ans[2]-ans[3];
 gA = (gA<0) ? gA + -1*(int)gA +1 : gA -(int)gA;
 dig=0;while(dig++ < 6 && tD++ < 1024) gA *=16, printf("%X",gA),gA -= (int)gA;
 d+=6,Co = 0;}

英特尔Quad核心上的运行时间= 8.06秒


这是代码高尔夫。通过使用简短的变量名并避免空格,尝试尽可能地压缩代码。例如,您可以使用printf("%X",(int)gA)而不是很长的列表来节省很多字符。
FUZxxl

1

PARI / GP-40个字节

此版本通过\x显示结果的十六进制数字“作弊” 。

\p8197
x=Pi<<4^6;x-=x\1;x=(x<<4^6)\1
\xx

此版本需要87字节才能以通常的方式转换为十六进制。

\p8197
x=Pi<<4^6;x-=x\1;concat([Vec("0123456789abcdef")[n+1]|n<-digits((x<<4^6)\1,16)])

两种版本的运行时间都只有一秒钟。


1

Perl-59

use ntheory"Pi";say substr int(Pi(3000)<<8192)->as_hex,1027

小于0.1s。


0

壳牌68

工具:bc -l,tr,剪切

echo "scale=2468;obase=16;4*a(1)"|bc -l|tr -d '\\\n'|cut -c1027-2051

Shell 64,工具:bc -l,tr,tail,最后一位的舍入有所不同

echo "scale=2466;obase=16;4*a(1)"|bc -l|tr -d '\\\n'|tail -c1024

可能会被认为是作弊行为,因为迭代计算了如何计算PI的知识在4 * a(1)中,并且必须使用scale = 2466来进行计算。

感谢面包箱的想法使用削减。


我不知道如何将其视为作弊;这些数字是在运行时计算的。尽管我应该注意,当我运行它时,它的输出在最后一位数字上有所不同(7而不是A)。顺便说一句,我想您可以将dd命令替换为tail -c1024以节省一些字符。
面包箱

是的,我也观察到了差异(并花了半小时:))。如果我告诉bc使用x位数的刻度,它将以十进制模式四舍五入到该位数,然后进行十六进制转换。因此,如果我再加上一位数字,它将产生69,而不是7。但是-在问题中未指定舍入样式或截断。并感谢您的尾随想法。:)
用户未知

问题指定:终止并产生与指定内容相同的输出。
FUZxxl 2012年

@FUZxxl:“应该...”,而不是“必须...”-我认为应该对检查十六进制转换是否运行良好以及跳过的字符数有所帮助,而不是作为规范的一部分,以符合1024的最后一位数字。但是我放弃并添加了16个字符来替换一个。
用户未知

1
鉴于该句子以“正式”一词开头,我同意OP可能在RFC的意义上表示它。此外,您还可以通过更换使用改进你的新的解决方案ddcut -c1027-2051。(shell提供了许多用于处理文本流的工具。)
面包箱2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.