Code Golf:MSM随机数生成器

时间:2010-04-23 23:19:15

标签: language-agnostic random code-golf rosetta-stone

挑战:

按字符数排序的最短代码,使用 Middle-Square Method 生成一系列(伪)随机数。

(伪)随机数生成的中等方法由John Von Neumann于1946年首次提出,其定义如下:

R n + 1 = mid((R n 2 ,m)

例如:

  

3456 2 = 11943936

     

mid(11943936)= 9439

     

9439 2 = 89094721

     

mid(89094721)= 0947

     

947 2 = 896809

     

mid(896809)= 9680

     

9680 2 = 93702400

     

mid(93702400)= 7024

另一个例子:

  

843 2 = 710649

     

mid(710649)= 106

     

106 2 = 11236

     

mid(11236)= 123

     

123 2 = 15129

     

mid(15129)= 512

     

512 2 = 262144

     

mid(262144)= 621

     

621 2 = 385641

     

mid(385641)= 856

     

856 2 = 732736

     

mid(732736)= 327

     

327 2 = 106929

     

mid(106929)= 069

     

69 2 = 4761

     

mid(4761)= 476

     

476 2 = 226576

     

mid(226576)= 265

mid的定义:

显然,mid的确切定义存在一些混淆。出于此挑战的目的,假设您提取与起始种子相同的位数。意思是,如果起始种子有4个数字,你将从中间提取4位数。如果起始种子有3个数字,您将从中间提取3位

如果在找不到确切的中间数时提取数字,请考虑数字 710649 。如果要提取中间3,则存在一些歧义( 106 064 )。在这种情况下,提取最接近字符串开头的3。因此,在这种情况下,您将提取 106

一种简单的方法是,如果数字不是正确的数字,则将零填充到数字。例如,如果您将前导零填充到 710649 ,则会获得 0710649 ,中间的3位数现在变为 106

测试用例:

不对种子的长度做出假设。例如,您不能假设种子将始终为4位数字

生成4位随机数的 3456 的起始种子应生成以下系列(前10个):

  

9439,947,9680,7024,33655,3232,4458,8737,3351,2292

生成4位数随机数的 8653 的起始种子应生成以下系列(前10个):

  

8744,4575,9306,6016,1922,6940,1636,6764,7516,4902

生成3位随机数的 843 的起始种子应生成以下系列(前10个):

  

106,123,512,621,856,327,69,476,265,22

45678 的起始种子生成5位数的乱序数应生成以下系列(前10位):

  

86479,78617,80632,1519,30736,47016,10504,3340,11556,35411

就前导零而言,答案是不应显示前导零:)。

15 个答案:

答案 0 :(得分:15)

Google文档 - 电子表格:42个字符

=MID(C2^2,LEN(C2^2)/2-LEN(C2)/2+1,LEN(C2))

<强>用法:

  • 将初始种子放入单元格C2,然后拖动所有序列的公式。

测试用例:

<强>截图:

Code Golf: MSM Random Number Generator http://img59.imageshack.us/img59/6830/golfo.png

<强>限制:

  • 此公式会保留前导零,但可以使用其他列修剪它们并在结果上应用INT()

答案 1 :(得分:10)

dc 26/37 chars

26 为单个数字列出函数:

?dZsl2^dZ1+ll-2/Ar^/All^%p
带有10个循环循环的

37 字符:

?dZsl[2^dZ1+ll-2/Ar^/All^%pdzB>L]dsLx

功能说明:

?            Input n
dZ           calculate number of digits
sl           store in register l
2^           calculate n^2
dZ           calculate number of digits of square
1+ll-2/Ar^/  n/(10^((squaredigits+1-l)/2)) int division truncates last digits 
All^%        n%(10^l) modulus truncates first digits
p            print the number

测试:

dc msml.dc
45678
86479
78617
80632
1519
30736
47016
10504
3340
11556
35411

答案 2 :(得分:5)

Python(86个字符)

r=input()
l=len(str(r))
while 1:
 x=str(r*r)
 y=(len(x)-l)/2
 r=int(x[y:y+l])
 print r

在stdout上生成无限序列。请注意,由于表示中的结尾long,反引号技巧至少在L类型的旧版本上不起作用。 Python 3 print作为函数将为关闭paren添加1个字符。

答案 3 :(得分:4)

C#( 96 81 79 85 84个字符


更改日志

  • 添加了Yuliy对81
  • 的建议
  • 删除了79的额外括号。
  • 增加计数因为我最初没有计算必要的空格(只有字符)。
  • 根据Camerons的建议,将1d替换为1。

我的代码:

    int F(int s, int l)
    {
        var r = "" + 1d*s*s;

        return int.Parse(r.Substring((r.Length - l) / 2, l));
    }

用法示例:

    int s = 8653;
    int l = 4;
    for(int i = 0; i< 10; i++)
    {
        s = F(s, l);
        Console.WriteLine(s);
    }

<强>结果

---8653---
8744
4575
9306
6016
1922
6940
1636
6764
7516
4902

---843---
106
123
512
621
856
327
69
476
265
22

---45678---
86479
78617
80632
1519
30736
47016
10504
3340
11556
35411

答案 4 :(得分:2)

Perl( 102 96 95 93 92 79 chars)

$s=$_;$d=length$s;map{$s*=$s;print 0+($s=substr$s,($s=~y///c-$d)/2,$d),$/}0..9

echo -n 3456 | perl -ne '$s=$_;$d=length$s;map{$s*=$s;print 0+($s=substr$s,($s=~y///c-$d)/2,$d),$/}0..9'
9439
947
9680
7024
3365
3232
4458
8737
3351
2292

答案 5 :(得分:1)

JavaScript:91个字符

function a(s,n){m=(s+'').length;while(n--)c=''+s*s,s=1*c.substr((c.length-m)/2,m);return s}

<强>用法:

a(3456, 4);     // 4th seed of 3456:   Returns: 7024
a(8653, 2);     // 2nd seed of 8653:   Returns: 4575
a(843, 10);     // 10th seed of 843:   Returns: 22
a(45678, 6);    // 6th seed of 45678:  Returns: 47016

完整测试案例

var tests = [3456, 8653, 843, 45678];

for (var i = 0; i < tests.length; i++) {
   console.log('-------------');
   console.log('| Seed: ' + tests[i]);
   console.log('-------------');

   for(var j = 1; j <= 10; j++) {
      console.log('| ' +  a(tests[i], j));
   }

   console.log('~~~~~~~~~~~~~');
}

测试结果:

-------------         -------------
| Seed: 3456          | Seed: 8653
-------------         -------------
| 9439                | 8744
| 947                 | 4575
| 9680                | 9306
| 7024                | 6016
| 3365                | 1922
| 3232                | 6940
| 4458                | 1636
| 8737                | 6764
| 3351                | 7516
| 2292                | 4902
~~~~~~~~~~~~~         ~~~~~~~~~~~~~

-------------         -------------
| Seed: 843           | Seed: 45678
-------------         -------------
| 106                 | 86479
| 123                 | 78617
| 512                 | 80632
| 621                 | 1519
| 856                 | 30736
| 327                 | 47016
| 69                  | 10504
| 476                 | 3340
| 265                 | 11556
| 22                  | 35411
~~~~~~~~~~~~~         ~~~~~~~~~~~~~

答案 6 :(得分:1)

Groovy - 82个字符

s=args[0]as int;def r(){f=s*s;g=f as String;t=g.size()/2;g=g[t-2..t+1];s=g as int}

使用第一个参数作为种子,输出由4个base10数字组成,如示例中所示..

答案 7 :(得分:1)

Haskell(97 99 chars)

可能仍然可以缩短。产生无限序列,或者至少它遇到0,在这种情况下它会崩溃。

i(f:l)x=x:i l(f x)
m n=head.filter((==n).length).i(cycle[init,tail])
b r n=n:b r(read$m r$show$n*n)

用法:b <length of number> <number>

*Main> b 5 45678
[45678,86479,78617,80632,1519,30736,47016,10504,3340,11556,35411...

<强>解释

该程序不是应用子字符串并使用字符串长度算术,而是在删除最后一个字符(init)和删除第一个字符(tail)之间进行迭代,直到达到所需的长度。

由于iterate以及大多数Haskell函数都假定使用的函数是常量。由于我们已经更改了函数本身,因此我们需要实现iterate的特殊版本。

答案 8 :(得分:1)

Perl,80个字符

(来自命令行)

$n=pop;$l=length$n;map{$n*=$n;print 0+($n=substr$n,(length($n)-$l)/2,$l),$/}0..9

答案 9 :(得分:1)

Ruby, 85 76 69个字符(生成并打印10个数字)

n=gets
l=n.size
10.times{n=n.to_i;x=(n*n).to_s;p n=x[(x.size-l)/2,l]}

从标准输入读取。

输出

> ruby rand.rb < 3456
9439
947
9680
7024
3365
3232
4458
8737
3351
2292

> ruby rand.rb < 8653
8744
4575
9306
6016
1922
6940
1636
6764
7516
4902

> ruby rand.rb < 843
106
123
512
621
856
327
69
476
265
22

> ruby rand.rb < 45678
86479
78617
80632
1519
30736
47016
10504
3340
11556
35411

答案 10 :(得分:1)

的Haskell


注意:生成包含MSM随机数的无限列表。


功能,81

l=length
m k n=take k$drop(div(l n-k)2)n
r n=iterate(read.m(l$show n).show.(^2))n

使用示例:

r 34562

示例输出:

[34562,94531,36109,3859,48918,92970,...

计划,103

l=length
m k n=take k$drop(div(l n-k)2)n
r n=iterate(read.m(l$show n).show.(^2))n
main=readLn>>=print.r

答案 11 :(得分:0)

Perl - 112 - 现在,108 - 现在95(感谢Zaid的想法) - 字符没有空白区域,不包括测试驱动程序循环(例如我只计算代码生成1个序列) - foreach循环体中的代码。

@s=(8653,843,45678,3456);
foreach $s (@s){
    for(0..9){$s*=$s;$l=length($s);$L||=($l+1)/2;$H=($l+$L+1)/2;
        $s=substr($s,-$H,$L)+0;
        print "$s,"
    }
    print "\n";
    $L=0; @S=(); # Reset for next loop
}

输出:

8744,4575,9306,6016,1922,6940,1636,6764,7516,4902,
106,123,512,621,856,327,69,476,265,22,
86479,78617,80632,1519,30736,47016,10504,3340,11556,35411,
9439,947,9680,7024,3365,3232,4458,8737,3351,2292,

压缩代码是112:

for(0..9){$s*=$s;$l=length($s);$L||=($l+1)/2;$H=($l+$L+1)/2;$s=substr($s,-$H,$L)+0;print "$s,"}

答案 12 :(得分:0)

Lua 135 128 114 chars)

function r(i)
l=string.len
b=i or b
s=i or s
p=s*s..""
e=(l(p)-l(b))/2
s=tonumber(p:sub(e+1,e+l(b)))
return s
end

具有一个参数的种子并返回第一个MSM随机整数;没有参数的后续调用返回下一个MSM随机整数。调用另一个整数来重新播种。

测试:

> =r(3456)
9439
> =r()
947
> =r()
9680
> =r()
7024
> =r()
3365
> =r()
3232
> =r()
4458
> =r()
8737
> =r()
3351
> =r()
2292
> =r(8653)
8744
> =r()
4575
> =r()
9306
> =r()
6016
> =r()
1922
> =r()
6940
> =r()
1636
> =r()
6764
> =r()
7516
> =r()
4902
> =r(843)
106
> =r()
123
> =r()
512
> =r()
621
> =r()
856
> =r()
327
> =r()
69
> =r()
476
> =r()
265
> =r()
22
> =r(45678)
86479
> =r()
78617
> =r()
80632
> =r()
1519
> =r()
30736
> =r()
47016
> =r()
10504
> =r()
3340
> =r()
11556
> =r()
35411
> 

答案 13 :(得分:0)

Ruby(66个字符)

假设整数输入:

def r s,l=s.to_s.size;x=(s*s).to_s;y=x.size;x[(y-l)/2,l].to_i;end

答案 14 :(得分:0)

Perl, 100 94 92 91 90 88 chars

通过标准输入提供种子。包含可读性的新行:

@n=($n=pop)=~/./g;
for(0..9){
    @s=$n**2=~/./g;
    $n=join$\,splice@s,(@s-@n)/2,@n;
    print$/,$n+0
}