天然皮#1-沙


9

目标

生成(N)个等长()的随机线段l,检查它们是否与等距(t)平行线交叉。

模拟

我们在模拟什么? 布冯的针。平滑沙盒中的沙子,画出一组等距的平行线(称为之间的距离t)。取直的长度l,将其N放到沙箱中。让它越过一条线的次数为c。然后Pi = (2 * l * n) / (t * c)

我们如何模拟这一点?

  • 接受输入 N,t,l
  • 随着N, t, l全部为正整数
  • 请执行以下N次数:
    • 生成均匀随机的整数坐标 x,y
    • 1 <= x, y <= 10^6
    • x,y 是长度的线段的中心 l
    • 生成均匀随机整数 a
    • 1 <= a <= 180
    • P线段与x轴交叉的点
    • 然后a是角度(x,y), P, (inf,0)
  • 计算与整数c相交的线段的数量,x = i*ti
  • 返回 (2 * l * N) / (t * c)

在此处输入图片说明

在此处输入图片说明

规格

  • 输入项
    • 灵活,可以采用任何标准方式(例如,函数参数,STDIN)和任何标准格式(例如,字符串,二进制)进行输入
  • 输出量
    • 灵活,以任何标准方式(例如退货,打印)提供输出
    • 可以使用空格,尾随和前导空格
    • 精度,请提供至少4位小数位数(即3.1416
  • 计分
    • 最短的代码胜出!

测试用例

由于随机的机会,您的输出可能与这些不一致。但平均而言,对于的给定值,您应该能获得如此高的准确性N, t, l

Input (N,t,l)    ->  Output 
-----------        ------
10,10,5          -> ?.????
10,100,50        -> ?.????
1000,1000,600    -> 3.????
10000,1000,700   -> 3.1???
100000,1000,700  -> 3.14??

TL; DR

这些挑战是仅需要自然和大脑(可能还有一些可重复使用的资源)才能逼近Pi的算法模拟。如果您在僵尸启示录期间确实需要Pi,那么这些方法不会浪费弹药!总共有九个挑战


我以为你已经做过第一了?
科纳·奥布莱恩

1
@ ConorO'Brien我对它XD 零索引
NonlinearFruit

问题是,在没有复数的语言中,您需要将数字0..180转换为0..pi,这违反了布冯针实验的目的。
水平河圣

@NonlinearFruit是否可以a通过其他方法创建方向(如果方向一致)?(想到2D高斯气泡)
Karl Napf

1
可以假设t > l吗?下面的两个解决方案进行了此假设,从而大大简化了交叉检查。
primo

Answers:


9

R,113 100 75 70 68 67 65 59 63 57字节

作为一种统计函数式编程语言,R很好地适合这种任务也就不足为奇了。大多数函数可以接受向量化输入的事实对于解决此问题确实很有帮助,因为N我们无需遍历迭代,而只需传递size的向量即可N。感谢@Billywob提供的一些建议可以减少4个字节。非常感谢@Primo耐心地向我解释了我的代码在where中已经无法t > l修复的情况下如何工作。

pryr::f(2*l*N/t/sum(floor(runif(N)+sinpi(runif(N))*l/t)))

在线尝试!

样本输出:

N=1000, t=1000, l=500
3.037975

N=10000, t=1000, l=700
3.11943

N=100000, t=1000, l=700
3.140351

说明

问题归结为确定x指针的两个值是否在平行线的两侧。这有一些重要的后果:

  1. y值无关紧要
  2. - x轴上的绝对位置无关紧要,仅相对于最接近的平行线的位置即可。

本质上,这是一维空间中的任务,我们在其中生成长度为[0,l](角度a确定该长度)的线,然后检查该长度超过多少倍t。粗略算法为:

  1. x1来自[0,1000000]的样本值。由于平行线出现在t沿x轴的每个th点上,因此相对x位置是xt
  2. 取样一个角度a
  3. x2根据来计算位置a
  4. 检查x1+x2适合多少次t,即取下地板(x1+x2)/t

采样N在[0,1E6]模数t相当于简单地采样N在[0,号码t]。由于(x1+x2)/t等价于x1/t + x2/t,第一步变为从[0,t] / t(即[0,1 ])采样。幸运的是,这是R runif函数的默认范围,该范围N从均匀分布返回0到1的实数。

                          runif(N)

我们重复此步骤以生成a针的角度。

                                         runif(N)

这些数字被解释为半圈(即.590度)。(OP要求从1到180度,但在注释中澄清了是否允许任何方法,只要精度更高或更精确即可。)对于角度θsin(θ)我们可以得到针头两端之间的x轴距离。(通常,您会使用余弦进行类似操作;但在我们的示例中,我们考虑的角度θ是相对于y轴而不是x轴的角度(也就是说,0度的值会上升,而不是),因此我们使用正弦,该正弦基本上使数字相移。)乘以l这可以得到x针头末端的位置。

                                   sinpi(runif(N))*l

现在我们除以t并添加x1值。这产生(x1+x2)/t,这是怎么远离针突出x1,以平行线数目方面。要获得越过多少行的整数,我们取floor

                    floor(runif(N)+sinpi(runif(N))*l/t)

我们计算总和,从而得出c针头横越多少行的计数。

                sum(floor(runif(N)+sinpi(runif(N))*l/t))

其余代码只是实现近似pi的公式(2*l*N)/(t*c)。利用以下事实,我们在括号中保存了一些字节(2*l*N)/(t*c) == 2*l*N/t/c

        2*l*N/t/sum(floor(runif(N)+sinpi(runif(N))*l/t))

整个过程被包装到一个匿名函数中:

pryr::f(2*l*N/t/sum(floor(runif(N)+sinpi(runif(N))*l/t)))

@rturnbull好一个!难道您不应该在一开始就跳过括号吗?(2*l*N) => 2*l*N
Billywob

@Billywob发现好!谢谢。
rturnbull

@rturnbull哦,而且,(2*l*N)/(t*c) = 2*l*N/t/c所以您也可以通过跳过最后一部分的括号来节省另外两个字节。
Billywob

@Billywob又一次,发现了!再次感谢。
rturnbull

1
@primo再次感谢,现在应该修复它。
rturnbull

6

Perl,97个字节

#!perl -p
/ \d+/;$_*=2*$'/$&/map{($x=(1+~~rand 1e6)/$&)-$a..$x+($a=$'/$&/2*sin~~rand(180)*71/4068)-1}1..$_

将shebang视为一个,输入取自标准输入,空格分隔。如果允许使用非整数随机值,则该值可能会短一些。

我采取了一种自由,将π/ 180近似为71/4068,准确度在1.48·10 -9以内。

样品用量

$ echo 1000000 1000 70000 | perl pi-sand.pl
3.14115345174061

数学上的等效替换

假设x坐标代表针的最左点,而不是问题描述中指定的中点:

89字节

#!perl -p
/ \d+/;$_*=2*$'/$&/map{($x=(1+~~rand 1e6)/$&)..$x+($'/$&*sin~~rand(180)*71/4068)-1}1..$_

问题指定x要作为随机整数进行采样。如果我们的项目行间距为一个的缺口,这将让我们与表单的值n/t0 <= n < t,不一定是均匀的,如果t没有平均分配1e6。假设均匀分布仍然可以接受:

76字节

#!perl -p
/ \d+/;$_*=2*$'/$&/map{($x=rand)..$x+($'/$&*sin~~rand(180)*71/4068)-1}1..$_

请注意,由于rand将始终小于1(因此会被截断为零),因此在范围开始时没有必要:

70字节

#!perl -p
/ \d+/;$_*=2*$'/$&/map{1..(rand)+($'/$&*sin~~rand(180)*71/4068)}1..$_

假设针的角度不必是整数度,而只需均匀地随机:

59个字节

#!perl -p
/ \d+/;$_*=2*$'/$&/map{1..(rand)+abs$'/$&*sin rand$`}1..$_

假设角度可以是任何均匀分布:

52个字节

#!perl -p
/ \d+/;$_*=2*$'/$&/map{1..(rand)+abs$'/$&*sin}1..$_

上面是布冯针的数学上正确的模拟。但是,在这一点上,我认为大多数人会同意这实际上不是问题所要的。


真的推了

每当第二个端点位于第一个端点的左侧时,我们就可以丢弃一半的测试用例(而不是交换它们):

47个字节

#!perl -p
/ \d+/;$_*=$'/$&/map{1..(rand)+$'/$&*sin}1..$_

请注意,和的值tl实验结果无关紧要。我们可以忽略它们(隐式假设它们相等):

28字节

#!perl -p
$_/=map{1..(rand)+sin}1..$_

显然没有竞争,但您必须承认,它确实具有一定的优雅。


4

Python 2,141字节

rtumbull的无耻端口,y由于完全不需要而已跳过。

from math import*
from random import*
lambda N,t,l:(2.*l*N)/(t*sum(randint(1,1e6)%t+abs(cos(randint(1,180)*pi/180))*l>t for _ in range(N)))

唯一的问题是,pi在程序中已为人所知。

在这里(可查询)具有未知的pi,没有三角函数

def g(N,t,l):
 c=0
 for _ in range(N):
    x,y=gauss(0,1),gauss(0,1);c+=randint(1,1e6)%t+abs(x/sqrt(x*x+y*y))*l>t
 return(2.*l*N)/(t*c)

x,yg只是为了方向。


需要from random import randint;from math import cos,pi。失败t < l例如1000000,1000,70000
primo
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.