Pseudorandom number generator image
- Task
Write a program that creates an image from a Pseudorandom Number Generator (PRNG) algorithm's output. The image can have the following dimensions:
- 250px by 250px : If the algorithm requires the use of prime numbers, use 8-15 bit primes.
- 500px by 500px : If the algorithm requires the use of prime numbers, use 8-15 bit primes.
- 1000px by 1000px : If the algorithm requires the use of prime numbers, use 8-32 bit primes.
- 1500px by 1500px : If the algorithm requires the use of prime numbers, use 16-64 bit primes.
- Possible Output
https://www.random.org/analysis/randbitmap-rdo.png
- See also
6502 Assembly
6502js/easy6502
The "hardware" gives us a memory-mapped port at address $00FE which contains a different random number every clock cycle. We can use this to write to video memory (there are only 16 colors so the top 4 bits of the random value are ignored.)
define vramPtr $00
define vramPtrHi $01
main:
;we're guaranteed to start off with all registers zeroed.
STA vramPtr
LDA #$02
STA vramPtrHi
LDX #4
loop:
LDA $FE ;read a random byte from the port
STA (vramPtr),y
INY
BNE loop
INC vramPtrHi
DEX
bne loop
brk ;end program
Output can be seen by copying/pasting the above code here.
Ada
-- Generate a (pseudo)random image
-- J. Carter 2023 Apr
-- Uses Ada_GUI (https://github.com/jrcarter/Ada_GUI)
with Ada.Numerics.Discrete_Random;
with Ada_GUI;
procedure Random_Image is
package Color_Random is new Ada.Numerics.Discrete_Random (Result_Subtype => Ada_GUI.RGB_Value);
Gen : Color_Random.Generator;
Image : Ada_GUI.Widget_ID;
Event : Ada_GUI.Next_Result_Info;
use type Ada_GUI.Event_Kind_ID;
begin -- Random_Image
Color_Random.Reset (Gen => Gen);
Ada_GUI.Set_Up (Title => "Random Image");
Image := Ada_GUI.New_Graphic_Area (Width => 250, Height => 250);
All_X : for X in 0 .. 249 loop
All_Y : for Y in 0 .. 249 loop
Image.Set_Pixel (X => X, Y => Y, Color => (Red => Color_Random.Random (Gen),
Green => Color_Random.Random (Gen),
Blue => Color_Random.Random (Gen),
Alpha => 1.0) );
end loop All_Y;
end loop All_X;
Wait : loop
Event := Ada_GUI.Next_Event;
exit Wait when not Event.Timed_Out and then Event.Event.Kind = Ada_GUI.Window_Closed;
end loop Wait;
Ada_GUI.End_GUI;
end Random_Image;
end.
- Output:
Delphi
program Pseudorandom_number_generator_image;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
vcl.Graphics,
Vcl.Imaging.PngImage;
type
TRGBTriple = packed record
b: Byte;
g: Byte;
r: Byte;
end;
PRGBTripleArray = ^TRGBTripleArray;
TRGBTripleArray = array[0..999] of TRGBTriple;
function Noise(cWidth, cHeight: Integer; Color: boolean = True): TBitmap;
const
Seed = 2147483647;
var
Pixels: PRGBTripleArray;
begin
RandSeed := Seed;
Result := TBitmap.Create;
with Result do
begin
SetSize(cWidth, cHeight);
PixelFormat := pf24bit;
for var row := 0 to cHeight - 1 do
begin
Pixels := ScanLine[row];
for var col := 0 to cWidth - 1 do
begin
if Color then
begin
Pixels[col].r := random(255);
Pixels[col].g := random(255);
Pixels[col].b := random(255);
end
else
begin
var Gray := Round((0.299 * random(255)) + (0.587 * random(255)) + (0.114
* random(255)));
Pixels[col].r := Gray;
Pixels[col].g := Gray;
Pixels[col].b := Gray;
end;
end;
end;
end;
end;
const
cWidth = 1000;
cHeight = 1000;
begin
// Color noise
var bmp := Noise(cWidth, cHeight);
bmp.SaveToFile('randbitmap-rdo.bmp');
// to Png
with TPngImage.create do
begin
Assign(bmp);
SaveToFile('randbitmap-rdo.png');
free;
end;
bmp.Free;
// Gray noise
bmp := Noise(cWidth, cHeight, False);
bmp.SaveToFile('randbitmap-rdo_g.bmp');
// to Png
with TPngImage.create do
begin
Assign(bmp);
SaveToFile('randbitmap-rdo_g.png');
free;
end;
bmp.Free;
end.
- Output:
Factor
Factor's default PRNG is Mersenne Twister, but it can be easily swapped out for others like Drand, Xoroshiro, Blum Blum Shub, lagged Fibonnaci, system RNGs, and more.
USING: accessors images.testing images.viewer literals math
random sequences ;
CONSTANT: size 500
<rgb-image>
${ size size } >>dim
size sq 3 * [ 256 random ] B{ } replicate-as >>bitmap
image-window
Forth
Uses gforth random generator to create PBM portable pixmap image file.
require random.fs
: prngimage
outfile-id >r
s" prngimage.pbm" w/o create-file throw to outfile-id
s\" P1\n500 500\n" type
500 0 do
500 0 do
2 random 48 + emit
loop #lf emit
loop
outfile-id close-file throw
r> to outfile-id ;
prngimage
FreeBASIC
Windowtitle "Pseudorandom number generator image"
Dim As Integer w = 500, h = w, x, y
Screenres w, h, 16
For x = 0 To w-1
For y = 0 To h-1
Pset(x, y), Rgb(Rnd * 255, Rnd * 255, Rnd * 255)
Next y
Next x
Bsave "Pseudo-Random-Algorithm.bmp",0
image500.png (sample image, offsite)
Go
The math/rand package uses a custom algorithm attributed to D.P.Mitchell and J.A.Reeds. It doesn't need to be seeded by a prime number. Typically (as here) the seed is generated from the current time.
The image is saved to a .png file which can then be viewed with a utility such as EOG.
package main
import (
"image"
"image/color"
"image/png"
"log"
"math/rand"
"os"
"time"
)
func main() {
rand.Seed(time.Now().UnixNano())
img := image.NewNRGBA(image.Rect(0, 0, 1000, 1000))
for x := 0; x < 1000; x++ {
for y := 0; y < 1000; y++ {
col := color.RGBA{uint8(rand.Intn(256)), uint8(rand.Intn(256)), uint8(rand.Intn(256)), 255}
img.Set(x, y, col)
}
}
fileName := "pseudorandom_number_generator.png"
imgFile, err := os.Create(fileName)
if err != nil {
log.Fatal(err)
}
defer imgFile.Close()
if err := png.Encode(imgFile, img); err != nil {
imgFile.Close()
log.Fatal(err)
}
}
Java
Following implementation generates images from java.util.Random(uses linear congruential generator [4].) and Blum Blum Shub Algorithm with least significant bit method and even bit parity method[5].
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.Random;
import java.util.Scanner;
/*
* Numbers to try:
* p = 11 or BigInteger.probablePrime(BIT1_LENGTH, rand)
* q = 23 or BigInteger.probablePrime(BIT_LENGTH, rand)
* seed = 3 or BigInteger.probablePrime(BIT_LENGTH,rand)
* */
public class csprngBBS {
public static Scanner input = new Scanner(System.in);
private static final String fileformat = "png";
private static String bitsStri = "";
private static String parityEven = "";
private static String leastSig = "";
private static String randomJavaUtil = "";
private static int width = 0;
private static int BIT_LENGTH = 0;
private static final Random rand = new SecureRandom();
private static BigInteger p = null; // 11
private static BigInteger q = null; // 23
private static BigInteger m = null;
private static BigInteger seed = null; // 3
private static BigInteger seedFinal = null;
private static final Random randMathUtil = new SecureRandom();
public static void main(String[] args) throws IOException {
System.out.print("Width: ");
width = input.nextInt();
System.out.print("Bit-Length: ");
BIT_LENGTH = input.nextInt();
System.out.print("Generator format: ");
String useGenerator = input.next();
p = BigInteger.probablePrime(BIT_LENGTH, rand);
q = BigInteger.probablePrime(BIT_LENGTH, rand);
m = p.multiply(q);
seed = BigInteger.probablePrime(BIT_LENGTH,rand);
seedFinal = seed.add(BigInteger.ZERO);
if(useGenerator.contains("parity") && useGenerator.contains("significant")) {
findLeastSignificant();
findBitParityEven();
createImage(parityEven, "parityEven");
createImage(leastSig, "significant");
}
if(useGenerator.contains("parity") && !useGenerator.contains("significant")){
findBitParityEven();
}
if(useGenerator.contains("significant") && !useGenerator.contains("parity")){
findLeastSignificant();
createImage(leastSig, "significant");
}
if(useGenerator.contains("util")){
findRandomJava(randMathUtil);
createImage(randomJavaUtil, "randomUtilJava");
}
}
public static void findRandomJava(Random random){
for(int x = 1; x <= Math.pow(width, 2); x++){
randomJavaUtil += random.nextInt(2);
}
}
public static void findBitParityEven(){
for(int x = 1; x <= Math.pow(width, 2); x++) {
seed = seed.pow(2).mod(m);
bitsStri = convertBinary(seed);
char[] bits = bitsStri.toCharArray();
int counter = 0;
for (char bit : bits) {
if (bit == '1') {
counter++;
}
}
if (counter % 2 != 0) {
parityEven += "1";
} else {
parityEven += "0";
}
}
}
public static void findLeastSignificant(){
seed = seedFinal;
for(int x = 1; x <= Math.pow(width, 2); x++){
seed = seed.pow(2).mod(m);
leastSig += bitsStri.substring(bitsStri.length() - 1);
}
}
public static String convertBinary(BigInteger value){
StringBuilder total = new StringBuilder();
BigInteger two = BigInteger.TWO;
while(value.compareTo(BigInteger.ZERO) > 0){
total.append(value.mod(two));
value = value.divide(two);
}
return total.reverse().toString();
}
public static void createImage(String useThis, String fileName) throws IOException {
int length = csprngBBS.width;
// Constructs a BufferedImage of one of the predefined image types.
BufferedImage bufferedImage = new BufferedImage(length, length, 1/*BufferedImage.TYPE_INT_RGB*/);
// Create a graphics which can be used to draw into the buffered image
Graphics2D g2d = bufferedImage.createGraphics();
for (int y = 1; y <= length; y++) {
for (int x = 1; x <= length; x++) {
if (useThis.startsWith("1")) {
useThis = useThis.substring(1);
g2d.setColor(Color.BLACK);
g2d.fillRect(x, y, 1, 1);
} else if (useThis.startsWith("0")) {
useThis = useThis.substring(1);
g2d.setColor(Color.WHITE);
g2d.fillRect(x, y, 1, 1);
}
}
System.out.print(y + "\t");
}
// Disposes of this graphics context and releases any system resources that it is using.
g2d.dispose();
// Save as file
File file = new File("REPLACEFILEPATHHERE" + fileName + "." + fileformat);
ImageIO.write(bufferedImage, fileformat, file);
}
}
jq
Works with jq and gojq, the C and Go implementations of jq
It has been claimed that the elementary cellular automaton with "Rule 30" can be used as a PRNG, (see e.g. Elementary_cellular_automaton/Random_number_generator), so this entry generates a set of (x,y,color) co-ordinates so that this hypothesis might be visually evaluated e.g. using the gnuplot program.
To keep things brief, the jq filter definitions at Elementary_cellular_automaton#jq are used but not repeated here.
include "elementary-cellular-automaton" {search : "."}; # the defs at [[Elementary_cellular_automaton#jq]]
def binary2number:
reduce (.[]|tonumber) as $x ({p:1}; .n += .p * $x | .p *= 2) | .n;
# Emit a stream of $n PRNGs in range(0;255)
def prng($n):
# 30 is 11110
("1" + 100 * "0" )
| [automaton(30; 8 * $n) | .[0:1]]
| _nwise(8) | binary2number ;
foreach prng(99*99) as $color ({x:0, y:1};
.color = $color
| .x += 1
| if .x == 100 then .x = 1 | .y += 1 else . end )
| "\(.x) \(.y) \(.color)"
Invocation:
jq -nrf program.jq > prng.txt gnuplot plot("prng.txt") with image pixels
Julia
Julia uses the Mersenne Twister algorithm for its default rand() function. That algorithm uses over 600 32-bit ints to represent its internal state, rather than just a product of two or three primes.
using FileIO, ImageIO
save("randombw.png", rand(Float16, 1000, 1000))
Lua
Lua uses the xoroshiro256**
algorithm.
size = 500
math.randomseed(os.time())
-- Writes a 256-bit grayscale PGM image file:
function writePgm(data, fn, comment)
local rows = #data
local cols = #data[1]
local file = io.open(fn, "wb")
-- Write header in ASCII
file:write("P5", "\n")
if comment ~= nil then
file:write("# ", comment, "\n")
end
file:write(cols, " ", rows, "\n")
file:write("255", "\n")
-- Write data in raw bytes
for _, r in ipairs(data) do
file:write(string.char(unpack(r)))
end
file:close()
end
img = {}
for r = 1, size do
img[r] = {}
for c = 1, size do
img[r][c] = math.random(0,255)
end
end
writePgm(img, "prng_img.pgm", string.format("PRNG Image (%d x %d)", size, size))
Maxima
genmatrix(lambda([i,j],random(1000)),1000,1000)$
wxdraw2d(image(%,0,0,30,30));

Nim
Nim standard PRNG is an implementation of the xoroshiro128+
(xor/rotate/shift/rotate) algorithm which is extremely fast. The standard library provides a Mersenne Twister implementation too. For this task, we used the first one.
import random
import imageman
const Size = 500
randomize()
var image = initImage[ColorRGBU](Size, Size)
for x in 0..<Size:
for y in 0..<Size:
let color = ColorRGBU([rand(255).byte, rand(255).byte, rand(255).byte])
image[x, y] = color
image.savePNG("prng_image.png", compression = 9)
Perl
Perl unified the PRNG with its own internal drand48() implementation on all platforms since v5.20.0. Without a manual srand, Perl by default source the seed from "/dev/urandom" if it is available so there shouldn't be any prime prerequisite.
use strict;
use warnings;
use GD;
my $img = GD::Image->new(500, 500, 1);
for my $y (0..500) {
for my $x (0..500) {
my $color = $img->colorAllocate(rand 256, rand 256, rand 256);
$img->setPixel($x, $y, $color);
}
}
open F, "image500.png";
print F $img->png;
image500.png (sample image, offsite)
Phix
-- demo\rosetta\Pseudorandom_number_generator_image.exw without js -- IupSaveImage(), not possible from within a browser (though a "save" button might be?) include pGUI.e IupOpen() integer w=250, h=w sequence bw = repeat(0,w*h) for x=0 to w-1 do for y=0 to h-1 do if rand(2)=2 then bw[x*h+y+1] = 255 end if end for end for Ihandle image = IupImage(w,h,bw) object res = IupSaveImage(image,"bw.png","PNG") IupClose()
PicoLisp
(seed (in "/dev/urandom" (rd 8)))
(out "image.pbm"
(prinl "P1")
(prinl 500 " " 500)
(do 500
(do 500
(prin (if (rand T) 1 0)) )
(prinl) ) )
Python
Libraries: Pillow, random# pseudorandom number image generator by Xing216
from random import randbytes
from PIL import Image
size = 1500
x = bytes.fromhex(" ".join([randbytes(3).hex() for x in range(size*size)]))
img = Image.frombuffer('RGB', (size, size), x, 'raw', 'RGB', 0, 1)
img.show()
Raku
MoarVM uses Mersenne Twister as its PRNG but a prime seeder is not mandatory.
# 20200818 Raku programming solution
use Image::PNG::Portable;
srand 2⁶³ - 25; # greatest prime smaller than 2⁶³ and the max my system can take
my @data = < 250 500 1000 1500 >;
@data.map: {
my $o = Image::PNG::Portable.new: :width($_), :height($_);
for ^$_ X ^$_ -> @pixel { # about 40% slower if split to ($x,$y) or (\x,\y)
$o.set: @pixel[0], @pixel[1], 256.rand.Int, 256.rand.Int, 256.rand.Int
}
$o.write: "image$_.png" or die;
}
- Output:
file image*.png image1000.png: PNG image data, 1000 x 1000, 8-bit/color RGBA, non-interlaced image1500.png: PNG image data, 1500 x 1500, 8-bit/color RGBA, non-interlaced image250.png: PNG image data, 250 x 250, 8-bit/color RGBA, non-interlaced image500.png: PNG image data, 500 x 500, 8-bit/color RGBA, non-interlaced
image500.png (sample image, offsite)
Sidef
require('GD')
var img = %O<GD::Image>.new(500, 500, 1)
for y in (0..500), x in (0..500) {
var color = img.colorAllocate(255.irand, 255.irand, 255.irand)
img.setPixel(x, y, color)
}
File("image500.png").write(img.png, :raw)
Wren
Wren's 'random' module uses the 'Well equidistributed long-period linear' (WELL512a) PRNG which doesn't need to be seeded with a prime number. It is in fact seeded from a sequence of 16 numbers but, if less are provided, the others are generated automatically. Typically (as here) the seed is generated from the current time.
import "dome" for Window
import "graphics" for Canvas, Color
import "random" for Random
class Game {
static init() {
Window.title = "Pseudorandom Number Generator Image"
Window.resize(1000, 1000)
Canvas.resize(1000, 1000)
var r = Random.new() // generates seed from current time
for (x in 0...1000) {
for (y in 0...1000) {
var c = Color.rgb(r.int(256), r.int(256), r.int(256))
Canvas.pset(x, y, c)
}
}
}
static update() {}
static draw(dt) {}
}
XPL0
The PRNG is linear congruential and is built-in. It's seeded with the time-of-day.
int X, Y;
[SetVid($11B); \VESA 1280x1024x24
for Y:= 0 to 1000-1 do
for X:= 0 to 1000-1 do
Point(X, Y, Ran($100_0000));
]
- Output:
Essentially the same as Delphi's image.