CJam,16 14 13字节
0{Kmr(+esmr}g
这将运行很长时间,因为它使用当前时间戳(大约10 12)来确定循环是否应该终止。我使用它作为提交内容,因为它是最短的,但是有两个14字节的替代方案,各有千秋:
0{esmr(+esmr}g
由于所有随机数的范围都取决于当前时间戳,因此此不受 PRNG周期的限制。因此,尽管负数或什至很小的正数的可能性将逐渐消失,但这应该能够产生任何数字。
下面是一个等效版本,它使用3e5
而不是时间戳。和20
用于第一范围(作为13字节的提交)。它不仅速度更快,而且符合所有规则。在保持合理的运行时间和较小的代码量的同时,获得超过1,000,000个数字的50%概率是一种极限情况。此版本的说明和数学依据:
0{Kmr(+3e5mr}g
这通常需要几秒钟来运行。您可以将替换为5
,2
以使其运行更快。但是,对于50%概率的要求只能满足1000,而不是1,000,000。
我从0开始。然后我有了一个循环,以1./(3*10 5)的概率冲出了这个循环。在该循环中,我向运行中的总数添加了一个介于-1和18(含)之间的随机整数。每个整数都有一个有限的(尽管很小)概率输出,正整数比负整数的可能性要大得多(我认为您一生中不会看到负整数)。以极小的概率突围,并在大多数时间增加(并增加而不是减少)可确保我们通常会超过1,000,000。
0 "Push a 0.";
{ }g "Do while...";
Kmr "Get a random integer in 0..19.";
( "Decrement to give -1..18.";
+ "Add.";
3e5mr "Get a random integer in 0..299,999. Aborts if this is 0.";
一些数学上的理由:
- 在每个步骤中,我们平均增加8.5。
- 要达到1,000,000,我们需要这些步骤中的117,647。
我们将执行少于此步骤数的概率为
sum(n=0..117,646) (299,999/300,000)^n * 1/300,000
计算结果为0.324402
。因此,在大约三分之二的情况下,我们将采取更多的117,647步,并且很容易地每执行1百万步。
- (请注意,这并不是确切的概率,因为这些平均值8.5会有一些波动,但是要达到50%,我们需要远远超过117,646到约210,000步。)
- 如有疑问,我们可以很容易地将终止概率的分母放大,
9e9
而无需添加任何字节(但需要运行年限)。
...或11个字节?
最后,有一个11字节的版本,它也不受PRNG周期的限制,但是每次都会耗尽内存。每次迭代仅生成一个随机数(基于时间戳),并将其用于递增和终止。每次迭代的结果都保留在堆栈中,并且仅在最后累加。感谢Dennis的想法:
{esmr(}h]:+