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.
- Middle-square_method Generator
- 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.
AArch64 Assembly
<lang 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" </lang>
~/.../rosetta/asm1 $ pRandom64 959861 333139 981593 524817 432883
Ada
<lang 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;</lang>
- Output:
959861 333139 981593 524817 432883
ALGOL 68
Uses (long) integers. <lang algol68>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</lang>
- Output:
959861 333139 981593 524817 432883
AppleScript
<lang 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</lang>
- Output:
<lang applescript>{959861, 333139, 981593, 524817, 432883}</lang>
ARM Assembly
<lang 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" </lang>
959861 333139 981593 524817 432883
AWK
<lang 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)
} </lang>
- Output:
1: 959861 2: 333139 3: 981593 4: 524817 5: 432883
C
<lang 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;
}</lang>
- Output:
959861 333139 981593 524817 432883
C++
<lang cpp>#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;
}</lang>
- Output:
959861 333139 981593 524817 432883
CLU
<lang 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</lang>
- Output:
959861 333139 981593 524817 432883
COBOL
<lang 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.</lang>
- Output:
959861 333139 981593 524817 432883
F#
<lang fsharp> // 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") </lang>
- Output:
959861 333139 981593 524817 432883
Factor
<lang 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</lang>
- Output:
959861 333139 981593 524817 432883
Forth
The loop keeps the seed on top of the stack. <lang forth>: next-random dup * 1000 / 1000000 mod ;
- 5-random-num 5 0 do next-random dup . loop ;
675248 5-random-num</lang>
- Output:
959861 333139 981593 524817 432883 ok
FreeBASIC
<lang 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 </lang>
Go
<lang 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) }
}</lang>
- Output:
959861 333139 981593 524817 432883
Haskell
<lang 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</lang>
- Output:
[959861,333139,981593,524817,432883]
J
<lang j>(_6{._3}.])&.:(10&#.^:_1)@(*~) ^: (>:i.6) 675248</lang>
- 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. <lang jq># 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)</lang>
- Output:
As expected.
Julia
<lang 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
</lang>
- Output:
959861 333139 981593 524817 432883
Nim
<lang nim>proc rand:int =
var seed {.global.} = 675248 seed = int(seed*seed) div 1000 mod 1000000 return seed
for _ in 1..5: echo rand()</lang>
- Output:
959861 333139 981593 524817 432883
Perl
<lang 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;</lang>
- 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
PureBasic
<lang 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</lang>
- Output:
1: 959861 2: 333139 3: 981593 4: 524817 5: 432883
Python
<lang python>seed = 675248 def random():
global seed s = str(seed ** 2) while len(s) != 12: s = "0" + s seed = int(s[3:9]) return seed
for i in range(0,5):
print(random())
</lang>
- Output:
959861 333139 981593 524817 432883
Raku
<lang perl6>sub msq {
state $seed = 675248; $seed = $seed² div 1000 mod 1000000;
}
say msq() xx 5;</lang>
- Output:
(959861 333139 981593 524817 432883)
Red
<lang rebol>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]</lang>
- Output:
959861 333139 981593 524817 432883
Ruby
<lang 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)</lang>
- Output:
959861 333139 981593 524817 432883
Sidef
<lang ruby>class MiddleSquareMethod(seed, k = 1000) {
method next { seed = (seed**2 // k % k**2) }
}
var obj = MiddleSquareMethod(675248) say 5.of { obj.next }</lang>
- Output:
[959861, 333139, 981593, 524817, 432883]
uBasic/4tH
<lang>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 (s*s/1000%1000000)</lang>
- Output:
959861 333139 981593 524817 432883 0 OK, 0:140
UNIX Shell
<lang bash>seed=675248 random(){
seed=`expr $seed \* $seed / 1000 % 1000000` return seed
} for ((i=1;i<=5;i++)); do
random echo $?
done</lang>
- Output:
The same as Python's
VBA
- See Visual Basic
Visual Basic
<lang vb>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</lang>
- Output:
As expected.
Wren
<lang ecmascript>var random = Fn.new { |seed| ((seed * seed)/1e3).floor % 1e6 }
var seed = 675248 for (i in 1..5) System.print(seed = random.call(seed))</lang>
- Output:
959861 333139 981593 524817 432883
XPL0
<lang 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, ^ )];
]</lang>
- Output:
959861 333139 981593 524817 432883