Code Golf: генератор случайных чисел MSM
Задача:
Самый короткий код по количеству символов, который будет генерировать ряд (псевдо) случайных чисел с помощью Метод Middle-Square.
Метод среднего квадрата генерации (псевдо) случайных чисел был впервые предложен Джоном Фон Нейманом в 1946 году и определяется следующим образом:
R n + 1= mid ((R n) 2 m)
Например:
3456 2= 11943936
середина (11943936) = 9439
9439 2= 89094721
середина (89094721) = 0947
947 2= 896809
середина (896809) = 9680
9680 2= 93702400
середина (93702400) = 7024
Другой пример:
843 2= 710649
середина (710649) = 106
106 2= 11236
середина (11236) = 123
123 2= 15129
середина (15129) = 512
512 2= 262144
середина (262144) = 621
621 2= 385641
середина (385641) = 856
856 2= 732736
середина (732736) = 327
327 2= 106929
середина (106929) = 069
69 2= 4761
середина (4761) = 476
476 2= 226576
середина (226576) = 265
Определение mid
:
По-видимому, существует некоторая путаница в отношении точного определения mid
. Для целей этой задачи предположим, что вы извлекаете то же количество цифр, что и начальное семя. Значение, если начальное семя имело 4 цифры, вы могли бы извлечь 4 цифры из середины. Если начальное семя имеет 3 цифры, вы можете извлечь 3 цифры из середины.
Что касается извлечения чисел, когда вы не можете найти точную середину, рассмотрите число 710649. Если вы хотите извлечь середину 3, есть некоторая двусмысленность (106 или 064). В этом случае извлеките 3, наиболее близкое к началу строки. Поэтому в этом случае вы извлечете 106.
Легкий способ подумать о том, чтобы положить нули в число, если это не правильное количество цифр. Например, если вы набрали начальные нули до 710649, вы получите 0710649, а средние 3 цифры теперь станут 106.
Тестовые примеры:
Не делайте никаких предположений относительно длины семени. Например, вы не можете предположить, что семя всегда будет 4-значным числом
Начальное семя 3456, которое генерирует 4-значные случайные числа, должно генерировать следующие серии (первые 10):
9439, 947, 9680, 7024, 3365, 3232, 4458, 8737, 3351, 2292
Начальное семя 8653, которое генерирует 4-значные случайные числа, должно генерировать следующую серию (первые 10):
8744, 4575, 9306, 6016, 1922, 6940, 1636, 6764, 7516, 4902
Начальное семя 843, которое генерирует 3-значные случайные числа, должно генерировать следующие серии (первые 10):
106, 123, 512, 621, 856, 327, 69, 476, 265, 22
Начальное семя 45678, которое генерирует 5-значные числа рядов, должно генерировать следующую серию (первые 10):
86479, 78617, 80632, 1519, 30736, 47016, 10504, 3340, 11556, 35411
Что касается ведущих нулей, то ответ не содержит ведущих нулей:).
Ответы
Ответ 1
dc 26/37 символов
26 отображает функцию для одного числа:
?dZsl2^dZ1+ll-2/Ar^/All^%p
37 символы с циклом из 10 циклов:
?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
Документы Google - таблица: 42 символа
=MID(C2^2,LEN(C2^2)/2-LEN(C2)/2+1,LEN(C2))
Применение:
- Поместите начальное семя в ячейку
C2
и перетащите формулу для всей последовательности.
Тестовые случаи:
Скриншот:
Code Golf: Генератор случайных чисел MSM http://img59.imageshack.us/img59/6830/golfo.png
Ограничения:
- Эта формула сохраняет ведущие нули, но их можно обрезать с помощью другого столбца и применить
INT()
к результатам.
Ответ 3
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. Обратите внимание, что трюк backtick не будет работать, по крайней мере, в более старых версиях с типом long
из-за окончания L
в представлении. Python 3 print
как функция добавит еще 1 char для закрытия патента.
Ответ 4
С# ( 96 81 79 85 84 символа)
Журнал изменений
- Добавлено предложение Yuliy для 81
- Удалены дополнительные скобки для 79.
- Увеличенный счет, потому что я изначально не подсчитал необходимые пробелы (только символы).
- Замена 1.0 на 1d по предложению Камеронов.
Мой код:
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
Ответ 5
Perl ( 102 96 95 93 92 79 символов)
$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
Ответ 6
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
~~~~~~~~~~~~~ ~~~~~~~~~~~~~
Ответ 7
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-мя базовыми цифрами 10, как в ваших примерах.
Ответ 8
символы Haskell (97 99)
Возможно, все еще можно сократить. Производит бесконечную последовательность или, по крайней мере, сталкивается с 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
) до достижения желаемой длины.
As iterate
, а также большинство функций Haskell предполагают, что используемая функция является постоянной. Поскольку мы сами меняем функцию, нам нужно реализовать специальную версию iterate
.
Ответ 9
Perl, 80 символов
(из командной строки)
$n=pop;$l=length$n;map{$n*=$n;print 0+($n=substr$n,(length($n)-$l)/2,$l),$/}0..9
Ответ 10
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
Ответ 11
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
Ответ 12
Perl - 112 - теперь 108 - теперь 95 (благодаря идее Заида) - символы без пробелов, исключая цикл тестового драйвера (например, я только подсчитал код для генерации 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,"}
Ответ 13
Lua ( 135 128 114 символов)
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
>
Ответ 14
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
Ответ 15
Perl, 100 94 92 91 90 88 символов
Семя предоставляется через стандартный вход. Новые строки включены для удобства чтения:
@n=($n=pop)=~/./g;
for(0..9){
@s=$n**2=~/./g;
$n=join$\,[email protected],(@[email protected])/2,@n;
print$/,$n+0
}