Pseudo-random numbers/Middle-square method
To generate a sequence of n-digit pseudorandom numbers, an n-digit starting value is created and squared, producing a 2n-digit number. If the result has fewer than 2n digits, leading zeroes are added to compensate. The middle n digits of the result would be the next number in the sequence and returned as the result. This process is then repeated to generate more numbers.
You are encouraged to solve this task according to the task description, using any language you may know.
This page uses content from Wikipedia. The original article was at Middle-square method. The list of authors can be seen in the page history. As with Rosetta Code, the text of Wikipedia is available under the GNU FDL. (See links for details on variance) |
- The Method
- Pseudo code
var seed = 675248 function random() var s = str(seed * seed) 'str: turn a number into string do while not len(s) = 12 s = "0" + s 'add zeroes before the string end do seed = val(mid(s, 4, 6)) 'mid: string variable, start, length 'val: turn a string into number return seed end function
- Middle-square method use
for i = 1 to 5 print random() end for
- Task
- Generate a class/set of functions that generates pseudo-random
numbers (6 digits) as shown above.
- Show the first five integers generated with the seed 675248 as shown above.
- Show your output here, on this page.
11l
F random()
V :seed = 675248
:seed = Int(String(Int64(:seed) ^ 2).zfill(12)[3 .+ 6])
R :seed
L 5
print(random())
- Output:
959861 333139 981593 524817 432883
AArch64 Assembly
/* ARM assembly AARCH64 Raspberry PI 3B */
/* program pRandom64.s */
/*******************************************/
/* Constantes file */
/*******************************************/
/* for this file see task include a file in language AArch64 assembly*/
.include "../includeConstantesARM64.inc"
/*********************************/
/* Initialized data */
/*********************************/
.data
sMessResult: .asciz " @ \n"
szCarriageReturn: .asciz "\n"
qSeed: .quad 675248
/*********************************/
/* UnInitialized data */
/*********************************/
.bss
sZoneConv: .skip 24
/*********************************/
/* code section */
/*********************************/
.text
.global main
main: // entry of program
ldr x0,qAdrqSeed
ldr x3,[x0]
mov x2,#5
1:
mov x0,x3
bl computePseudo
mov x3,x0
ldr x1,qAdrsZoneConv
bl conversion10 // call décimal conversion
ldr x0,qAdrsMessResult
ldr x1,qAdrsZoneConv // insert conversion in message
bl strInsertAtCharInc
bl affichageMess // display message
subs x2,x2,#1
bgt 1b
100: // standard end of the program
mov x0, #0 // return code
mov x8, #EXIT // request to exit program
svc #0 // perform the system call
qAdrszCarriageReturn: .quad szCarriageReturn
qAdrsMessResult: .quad sMessResult
qAdrsZoneConv: .quad sZoneConv
qAdrqSeed: .quad qSeed
/***************************************************/
/* compute pseudo random number */
/***************************************************/
/* x0 contains the number */
computePseudo:
stp x1,lr,[sp,-16]! // save registers
stp x2,x3,[sp,-16]! // save registers
mov x2,x0
mul x0,x2,x2
ldr x2,qdiv
udiv x1,x0,x2
ldr x2,qdiv2
udiv x0,x1,x2
msub x0,x2,x0,x1
ldp x2,x3,[sp],16 // restaur 2 registers
ldp x1,lr,[sp],16 // restaur 2 registers
ret // return to address lr x30
qdiv: .quad 1000
qdiv2: .quad 1000000
/********************************************************/
/* File Include fonctions */
/********************************************************/
/* for this file see task include a file in language AArch64 assembly */
.include "../includeARM64.inc"
~/.../rosetta/asm1 $ pRandom64 959861 333139 981593 524817 432883
Ada
with Ada.Text_IO; use Ada.Text_IO;
procedure Main is
type long is range 0 .. 2**64;
Seed : long := 675_248;
function random return long is
begin
Seed := Seed * Seed / 1_000 rem 1_000_000;
return Seed;
end random;
begin
for I in 1 .. 5 loop
Put (long'Image (random));
end loop;
New_Line;
end Main;
- Output:
959861 333139 981593 524817 432883
ALGOL 68
Uses (long) integers.
BEGIN # generate random numbers by the middle-square method #
INT seed := 675248;
# returns the next middle-square random number #
PROC ms random = INT: seed := SHORTEN( ( ( LONG INT( seed ) * LONG INT( seed ) ) OVER 1000 ) MOD 1 000 000 );
# test the ms random procedure #
FOR i TO 5 DO
print( ( " ", whole( ms random, 0 ) ) )
OD
END
- Output:
959861 333139 981593 524817 432883
AppleScript
on newGenerator(n, seed)
script generator
property seed : missing value
property p1 : 10 ^ (n div 2)
property p2 : 10 ^ n
on getRandom()
set seed to seed * seed div p1 mod p2
return seed div 1
end getRandom
end script
set generator's seed to seed mod (10 ^ n)
return generator
end newGenerator
local generator, output
set generator to newGenerator(6, 675248)
set output to {}
repeat 5 times
set end of output to generator's getRandom()
end repeat
return output
- Output:
{959861, 333139, 981593, 524817, 432883}
ARM Assembly
/* ARM assembly Raspberry PI or android with termux */
/* program pRandom.s */
/* REMARK 1 : this program use routines in a include file
see task Include a file language arm assembly
for the routine affichageMess conversion10
see at end of this program the instruction include */
/* for constantes see task include a file in arm assembly */
/************************************/
/* Constantes */
/************************************/
.include "../constantes.inc"
/*********************************/
/* Initialized data */
/*********************************/
.data
sMessResult: .asciz " @ \n"
szCarriageReturn: .asciz "\n"
iSeed: .int 675248
/*********************************/
/* UnInitialized data */
/*********************************/
.bss
sZoneConv: .skip 24
/*********************************/
/* code section */
/*********************************/
.text
.global main
main: @ entry of program
ldr r0,iAdriSeed
ldr r3,[r0]
mov r2,#5
1:
mov r0,r3
bl computePseudo
mov r3,r0
ldr r1,iAdrsZoneConv
bl conversion10 @ call décimal conversion
ldr r0,iAdrsMessResult
ldr r1,iAdrsZoneConv @ insert conversion in message
bl strInsertAtCharInc
bl affichageMess @ display message
subs r2,r2,#1
bgt 1b
100: @ standard end of the program
mov r0, #0 @ return code
mov r7, #EXIT @ request to exit program
svc #0 @ perform the system call
iAdrszCarriageReturn: .int szCarriageReturn
iAdrsMessResult: .int sMessResult
iAdrsZoneConv: .int sZoneConv
iAdriSeed: .int iSeed
/***************************************************/
/* compute pseudo random number */
/***************************************************/
/* r0 contains the number */
computePseudo:
push {r1-r2,lr} @ save registers
mov r2,r0
umull r0,r1,r2,r2
ldr r2,idiv
bl division32R
ldr r2,idiv2
bl division32R
mov r0,r2
pop {r1-r2,pc} @ restaur registers
idiv: .int 1000
idiv2: .int 1000000
/***************************************************/
/* division number 64 bits in 2 registers by number 32 bits */
/***************************************************/
/* r0 contains lower part dividende */
/* r1 contains upper part dividende */
/* r2 contains divisor */
/* r0 return lower part quotient */
/* r1 return upper part quotient */
/* r2 return remainder */
division32R:
push {r3-r9,lr} @ save registers
mov r6,#0 @ init upper upper part remainder !!
mov r7,r1 @ init upper part remainder with upper part dividende
mov r8,r0 @ init lower part remainder with lower part dividende
mov r9,#0 @ upper part quotient
mov r4,#0 @ lower part quotient
mov r5,#32 @ bits number
1: @ begin loop
lsl r6,#1 @ shift upper upper part remainder
lsls r7,#1 @ shift upper part remainder
orrcs r6,#1
lsls r8,#1 @ shift lower part remainder
orrcs r7,#1
lsls r4,#1 @ shift lower part quotient
lsl r9,#1 @ shift upper part quotient
orrcs r9,#1
@ divisor sustract upper part remainder
subs r7,r2
sbcs r6,#0 @ and substract carry
bmi 2f @ négative ?
@ positive or equal
orr r4,#1 @ 1 -> right bit quotient
b 3f
2: @ negative
orr r4,#0 @ 0 -> right bit quotient
adds r7,r2 @ and restaur remainder
adc r6,#0
3:
subs r5,#1 @ decrement bit size
bgt 1b @ end ?
mov r0,r4 @ lower part quotient
mov r1,r9 @ upper part quotient
mov r2,r7 @ remainder
100: @ function end
pop {r3-r9,lr} @ restaur registers
bx lr
/***************************************************/
/* ROUTINES INCLUDE */
/***************************************************/
.include "../affichage.inc"
959861 333139 981593 524817 432883
Arturo
seed: 675248
rand: function => [
let 'seed <= ((seed^2) / 1000) % 1000000
]
do.times: 5 -> print rand
- Output:
959861 333139 981593 524817 432883
AWK
# syntax: GAWK -f PSEUDO-RANDOM_NUMBERS_MIDDLE-SQUARE_METHOD.AWK
BEGIN {
seed = 675248
srand(seed)
for (i=1; i<=5; i++) {
printf("%2d: %s\n",i,main())
}
exit(0)
}
function main( s) {
s = seed ^ 2
while (length(s) < 12) {
s = "0" s
}
seed = substr(s,4,6)
return(seed)
}
- Output:
1: 959861 2: 333139 3: 981593 4: 524817 5: 432883
BASIC
FreeBASIC
Dim Shared seed As Integer = 675248
Dim i As Integer
Declare Function Rand As Integer
For i = 1 To 5
Print Rand
Next i
Sleep
Function Rand As Integer
Dim s As String
s = Str(seed ^ 2)
Do While Len(s) <> 12
s = "0" + s
Loop
seed = Val(Mid(s, 4, 6))
Rand = seed
End Function
PureBasic
Procedure.i MSRandom()
Static.i seed=675248
seed = (seed*seed/1000)%1000000
ProcedureReturn seed
EndProcedure
If OpenConsole()
For i=1 To 5 : PrintN(Str(i)+": "+Str(MSRandom())) : Next
Input()
EndIf
- Output:
1: 959861 2: 333139 3: 981593 4: 524817 5: 432883
uBasic/4tH
If Info("wordsize") < 64 Then Print "This needs a 64-bit uBasic" : End
s = 675248
For i = 1 To 5
Print Set(s, FUNC(_random(s)))
Next
End
_random Param (1) : Return (a@*a@/1000%1000000)
- Output:
959861 333139 981593 524817 432883 0 OK, 0:140
Visual Basic
Option Explicit
Dim seed As Long
Sub Main()
Dim i As Integer
seed = 675248
For i = 1 To 5
Debug.Print Rand
Next i
End Sub
Function Rand() As Variant
Dim s As String
s = CStr(seed ^ 2)
Do While Len(s) <> 12
s = "0" + s
Loop
seed = Val(Mid(s, 4, 6))
Rand = seed
End Function
- Output:
As expected.
bc
s = 675248
define r() {
s = s * s / 1000 % 1000000
return(s)
}
for (i = 0; i != 5; ++i) r()
- Output:
959861 333139 981593 524817 432883
C
#include<stdio.h>
long long seed;
long long random(){
seed = seed * seed / 1000 % 1000000;
return seed;
}
int main(){
seed = 675248;
for(int i=1;i<=5;i++)
printf("%lld\n",random());
return 0;
}
- Output:
959861 333139 981593 524817 432883
C++
#include <exception>
#include <iostream>
using ulong = unsigned long;
class MiddleSquare {
private:
ulong state;
ulong div, mod;
public:
MiddleSquare() = delete;
MiddleSquare(ulong start, ulong length) {
if (length % 2) throw std::invalid_argument("length must be even");
div = mod = 1;
for (ulong i=0; i<length/2; i++) div *= 10;
for (ulong i=0; i<length; i++) mod *= 10;
state = start % mod;
}
ulong next() {
return state = state * state / div % mod;
}
};
int main() {
MiddleSquare msq(675248, 6);
for (int i=0; i<5; i++)
std::cout << msq.next() << std::endl;
return 0;
}
- Output:
959861 333139 981593 524817 432883
CLU
middle_square = cluster is seed, next
rep = null
own state: int
seed = proc (s: int)
state := s
end seed
next = proc () returns (int)
state := (state ** 2) / 1000 // 1000000
return(state)
end next
end middle_square
start_up = proc ()
po: stream := stream$primary_output()
middle_square$seed(675248)
for i: int in int$from_to(1, 5) do
stream$putl(po, int$unparse(middle_square$next()))
end
end start_up
- Output:
959861 333139 981593 524817 432883
COBOL
IDENTIFICATION DIVISION.
PROGRAM-ID. MIDDLE-SQUARE.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 STATE.
03 SEED PIC 9(6) VALUE 675248.
03 SQUARE PIC 9(12).
03 FILLER REDEFINES SQUARE.
05 FILLER PIC 9(3).
05 NEXT-SEED PIC 9(6).
05 FILLER PIC 9(3).
PROCEDURE DIVISION.
BEGIN.
PERFORM SHOW-NUM 5 TIMES.
STOP RUN.
SHOW-NUM.
PERFORM MAKE-RANDOM.
DISPLAY SEED.
MAKE-RANDOM.
MULTIPLY SEED BY SEED GIVING SQUARE.
MOVE NEXT-SEED TO SEED.
- Output:
959861 333139 981593 524817 432883
dc
675248 5 sn
[d * 1000 / 1000000 %] sr
[lr x p ln 1 - d sn 0 <l] d sl x
- Output:
959861 333139 981593 524817 432883
EasyLang
global seed .
seed = 675248
func rand . randNum .
strSeed$ = seed
s$ = seed * seed
while not len s$ = len strSeed$ * 2
s$ = "0" & s$
.
seed = number substr s$ (len strSeed$ / 2 + 1) len strSeed$
randNum = seed
.
for i = 1 to 5
call rand randNum
print randNum
.
- Output:
959861 333139 981593 524817 432883
F#
// Pseudo-random numbers/Middle-square method. Nigel Galloway: January 5th., 2022
Seq.unfold(fun n->let n=n*n%1000000000L/1000L in Some(n,n)) 675248L|>Seq.take 5|>Seq.iter(printfn "%d")
- Output:
959861 333139 981593 524817 432883
Factor
USING: kernel math namespaces prettyprint ;
SYMBOL: seed
675248 seed set-global
: rand ( -- n ) seed get sq 1000 /i 1000000 mod dup seed set ;
5 [ rand . ] times
- Output:
959861 333139 981593 524817 432883
Forth
The loop keeps the seed on top of the stack.
: next-random dup * 1000 / 1000000 mod ;
: 5-random-num 5 0 do next-random dup . loop ;
675248 5-random-num
- Output:
959861 333139 981593 524817 432883 ok
Go
package main
import "fmt"
func random(seed int) int {
return seed * seed / 1e3 % 1e6
}
func main() {
seed := 675248
for i := 1; i <= 5; i++ {
seed = random(seed)
fmt.Println(seed)
}
}
- Output:
959861 333139 981593 524817 432883
Haskell
findPseudoRandom :: Int -> Int
findPseudoRandom seed =
let square = seed * seed
squarestr = show square
enlarged = replicate ( 12 - length squarestr ) '0' ++ squarestr
in read $ take 6 $ drop 3 enlarged
solution :: [Int]
solution = tail $ take 6 $ iterate findPseudoRandom 675248
- Output:
[959861,333139,981593,524817,432883]
J
(_6{._3}.])&.:(10&#.^:_1)@(*~) ^: (>:i.6) 675248
- Output:
959861 333139 981593 524817 432883 387691
jq
Works with gojq, the Go implementation of jq
The proposed PRNG hardly deserves the name and so this entry avoids it.
# Input: a positive integer
# Output: the "middle-square"
def middle_square:
(tostring|length) as $len
| (. * .)
| tostring
| (3*length/4|ceil) as $n
| .[ -$n : $len-$n]
| if length == 0 then 0 else tonumber end;
# Input: a positive integer
# Output: middle_square, applied recursively
def middle_squares:
middle_square | ., middle_squares;
limit(5; 675248 | middle_squares)
- Output:
As expected.
Julia
const seed = [675248]
function random()
s = string(seed[] * seed[], pad=12) # turn a number into string, pad to 12 digits
seed[] = parse(Int, s[begin+3:end-3]) # take middle of number string, parse to Int
return seed[]
end
# Middle-square method use
for i = 1:5
println(random())
end
- Output:
959861 333139 981593 524817 432883
Lambdatalk
{def randoms
{lambda {:s :n}
{if {>= :n 0}
then :s
{randoms {W.pad {% {floor {/ {* :s :s} 1.e3}} 1.e6} 6}
{- :n 1}}
else}}}
-> randoms
{randoms 675248 100}
->
675248 959861 333139 981593 524817 432883 387691 304311 605184 247673 341914 905183 356263 923325 529055 899193 548051 359898 526570 275964 156129 376264 574597 161712 150770 731592 226854 462737 125531 758031 610996 316112 926796 950825 681806 859421 604455 365847 844027 381576 600243 291659 649726 143875 700015 210006 102520 510350 457122 960522 602512 207106 892895 261481 372313 616969 650746 470356 234766 115074 242025 576100 891210 255264 159709 506964 124976 619000 161000 921000 241000 810006 109720 384786 602656 194254 734616 660667 480884 249421 210835 451397 759251 462081 518850 205322 157123 687637 844643 421797 912709 377186 269278 510641 754230 862892 582603 426255 693325 699555 377198
Miranda
main :: [sys_message]
main = [Stdout (lay (map show numbers))]
where numbers = take 5 (randoms 6 seed)
seed = 675248
randoms :: num->num->[num]
randoms sz = tl . iterate (msq sz)
msq :: num->num->num
msq sz seed = sq div (10^(sz div 2)) mod 10^sz
where sq = seed^2
- Output:
959861 333139 981593 524817 432883
Nim
proc rand:int =
var seed {.global.} = 675248
seed = int(seed*seed) div 1000 mod 1000000
return seed
for _ in 1..5: echo rand()
- Output:
959861 333139 981593 524817 432883
OCaml
let random_seq seed =
let next x = x * x / 1000 mod 1000_000 in
Seq.iterate next (next seed)
(* test *)
let () =
random_seq 675248 |> Seq.take 5 |> Seq.iter (Printf.printf " %u")
- Output:
959861 333139 981593 524817 432883
Perl
#!/usr/bin/perl
use strict; # https://rosettacode.org/wiki/Pseudo-random_numbers/Middle-square_method
use warnings;
sub msq
{
use feature qw( state );
state $seed = 675248;
$seed = sprintf "%06d", $seed ** 2 / 1000 % 1e6;
}
print msq, "\n" for 1 .. 5;
- Output:
959861 333139 981593 524817 432883
Phix
You don't actually have to use strings, but should you so desire the commented-out line gives exactly the same results. Output matches Python.
with javascript_semantics integer seed = 675248 function random() seed = remainder(floor(seed*seed/1000),1e6) -- seed = to_integer(sprintf("%012d",seed*seed)[4..9]) return seed end function for i=1 to 5 do ?random() end for
Python
seed = 675248
def random():
global seed
seed = int(str(seed ** 2).zfill(12)[3:9])
return seed
for _ in range(5):
print(random())
- Output:
959861 333139 981593 524817 432883
Quackery
As specified in task pseudo-code.
(Adding one zero at a time irks me. If I wasn't sticking strictly to the pseudo-code I'd have written 12 over size - char 0 swap of join
instead of the while
loop – i.e. calculate how many 0s are required and add that many in one hit.
Or even "add more than enough 0s and then truncate". $ "000000000000" join 12 split drop
.)
[ dip [ split nip ]
split drop ] is mid ( [ n n --> [ )
[ stack 675248 ] is seed ( --> n )
[ seed take
dup * number$
[ dup size 12 != while
char 0 join
again ]
3 6 mid $->n drop
dup seed put ] is rand ( --> n )
5 times [ rand echo sp ]
Divide and modulo.
[ stack 675248 ] is seed ( --> s )
[ seed take
dup * 1000 /
1000000 mod
dup seed put ] is rand ( --> n )
5 times [ rand echo sp ]
- Output:
For both versions.
959861 333139 981593 524817 432883
Raku
sub msq {
state $seed = 675248;
$seed = $seed² div 1000 mod 1000000;
}
say msq() xx 5;
- Output:
(959861 333139 981593 524817 432883)
Red
Red[]
seed: 675248
rand: does [seed: to-integer (seed * 1.0 * seed / 1000) % 1000000] ; multiply by 1.0 to avoid integer overflow (32-bit)
loop 5 [print rand]
- Output:
959861 333139 981593 524817 432883
Ruby
def middle_square (seed)
return to_enum(__method__, seed) unless block_given?
s = seed.digits.size
loop { yield seed = (seed*seed).to_s.rjust(s*2, "0")[s/2, s].to_i }
end
puts middle_square(675248).take(5)
- Output:
959861 333139 981593 524817 432883
Sidef
class MiddleSquareMethod(seed, k = 1000) {
method next {
seed = (seed**2 // k % k**2)
}
}
var obj = MiddleSquareMethod(675248)
say 5.of { obj.next }
- Output:
[959861, 333139, 981593, 524817, 432883]
UNIX Shell
seed=675248
random(){
seed=`expr $seed \* $seed / 1000 % 1000000`
return seed
}
for ((i=1;i<=5;i++));
do
random
echo $?
done
- Output:
The same as Python's
VBA
- See Visual Basic
Wren
var random = Fn.new { |seed| ((seed * seed)/1e3).floor % 1e6 }
var seed = 675248
for (i in 1..5) System.print(seed = random.call(seed))
- Output:
959861 333139 981593 524817 432883
XPL0
real Seed;
func Random;
[Seed:= Floor(Mod(Seed*Seed/1e3, 1e6));
return fix(Seed);
];
int N;
[Seed:= 675248.;
for N:= 1 to 5 do
[IntOut(0, Random); ChOut(0, ^ )];
]
- Output:
959861 333139 981593 524817 432883