# PsMWC32.ps1 # PowerShell script to generate psuedo random numbers using # a 32-bit Multiply With Carry Generator. # # ---------------------------------------------------------------------- # Copyright (c) 2021 Richard L. Mueller # Hilltop Lab web site - http://www.rlmueller.net # Version 1.0 - December 6, 2021 # # You have a royalty-free right to use, modify, reproduce, and # distribute this script file in any way you find useful, provided that # you agree that the copyright owner above has no warranty, obligations, # or liability for such use. Param ( [Int32]$Count, [Int64]$Seed, [Int64]$Carry ) Function Syntax ($ErrNum) { # Subroutine to display error messages and syntax help. Switch ($ErrNum) { 1 {Write-Host "Error, too many arguments." -ForegroundColor Red -backgroundColor Black} 2 {Write-Host "Error, seed must be greater than or equal to 0." -ForegroundColor Red -backgroundColor Black} 3 {Write-Host "Error, seed must be less than 2^32 (4,294,967,296)" -ForegroundColor Red -backgroundColor Black} 4 {Write-Host "Error, count must be positive." -ForegroundColor Red -backgroundColor Black} 5 {Write-Host "Error, carry must be greater than or equal to 0." -ForegroundColor Red -backgroundColor Black} 6 {Write-Host "Error, carry must be less than 2^32 (4,294,967,296)." -ForegroundColor Red -backgroundColor Black} 7 {Write-Host "Error, carry cannot be A - 1 = 4,164,903,689." -ForegroundColor Red -backgroundColor Black} } Write-Host "-----" Write-Host "PsMWC32.ps1 - PowerShell program to generate random numbers." Write-Host "Syntax:" Write-Host " PowerShell .\PsMWC32.ps1 " Write-Host "where:" Write-Host " is number of random integers to display (optional)." Write-Host " Count must be a positive integer, with no commas." Write-Host " Default value is 10." Write-Host " is a seed value (optional)." Write-Host " Seed must be an integer greater than or equal to 0" Write-Host " and less than 2^32 (no commas). Default value is based" Write-Host " on the system timer." Write-Host " a carry value (optional)." Write-Host " Carry must be an integer greater than or equal to 0" Write-Host " and less than 2^32 (no commas). Default value is 2,634,046,488" Write-Host "Program outputs psuedo random integers greater than or equal" Write-Host "to 0 and less than 2^32 (4,294,967,296)." Write-Host "Copyright(c) 2021 Richard L. Mueller" Write-Host "Version 1.0 - December 6, 2021" Return $True } # Use default if parmeter not specified. # Default count is 10. If ($Count -eq 0) {$Count = 10} # Default Seed is based on the system time since midnight in seconds. If ($Seed -eq 0) { $D1 = [Int16](Get-Date -Format HH) $D2 = [Int16](Get-Date -Format mm) $D3 = [Int16](Get-Date -Format ss) $D4 = $D3 + (60 * ($D2 + (60 * $D1))) $D5 = $D4 * 4294967296 $Seed = [System.Math]::Truncate($D5 / (24 * 60 * 60)) } # The default initial carry is based on the system date and time. If ($Carry -eq 0) { $D1 = [Int16](Get-Date -Format MM) $D2 = [Int16](Get-Date -Format dd) $D3 = [Int16](Get-Date -Format yy) $D4 = [Int16](Get-Date -Format HH) $D5 = [Int16](Get-Date -Format mm) $D6 = [Int16](Get-Date -Format ss) $D7 = ($D6 + (60 * $D5) + (3600 * $D4)) / (24 * 3600) $D8 = $D2 + ($D1 * 30) + ($D3 * 365) + 36505 $D9 = [System.Math]::Truncate(($D7 + $D8) * 100000000000) $D10 = [System.Math]::Truncate($D9 / 4294967296) $Carry = $D9 - (4294967296 * $D10) } # Validate arguments. If ($Args.Count -gt 0) {If (Syntax 1) {Exit}} If ($Seed -lt 0) {If (Syntax 2) {Exit}} If (($Seed - 4294967296) -gt 0) {If (Syntax 3) {Exit}} If ($Count -lt 0) {If (Syntax 4) {Exit}} If ($Carry -lt 0) {If (Syntax 5) {Exit}} If (($Carry - 4294967296) -gt 0) {If (Syntax 6) {Exit}} # Carry cannot be 0 or A - 1 = 4,164,903,689. If ($Carry -eq 4164903689) {If (Syntax 7) {Exit}} # Output the initial seed and carry values. "Initial Seed = " + '{0:n0}' -f $Seed + " Initial Carry = " + '{0:n0}' -f $Carry # Display number of integers requested from the psuedo random number generator. "$Count psuedo random integers:" " " Function MWC ([Int64]$X, [Int64]$C) { # Constants. # $A = 4,164,903,690 # $M = 4,294,967,296 # $H = 65,536 $A_hi = 63551 $A_lo = 25354 [Int64]$M = 4294967296 $H = 65536 $X_hi = [System.Math]::Truncate($X / $H) $X_lo = $X - ($X_hi * $H) $C_hi = [System.Math]::Truncate($C / $H) $C_lo = $C - ($C_hi * $H) # $A = (($A_hi * $H) + $A_lo) # $X = (($X_hi * $H) + $X_lo) # $C = (($C_hi * $H) + $C_lo) [Int64]$F1 = $A_hi * $X_hi [Int64]$F2 = ($A_hi * $X_lo) + ($A_lo * $X_hi) + $C_hi [Int64]$F3 = ($A_lo * $X_lo) + $C_lo [Int64]$T1 = [System.Math]::Truncate($F2 / $H) [Int64]$T2 = $M * $T1 [Int64]$Xn = ((($F2 * $H) % $M) + $F3) % $M [Int64]$Cn = [System.Math]::Truncate(($F2 / $H) + $F1) Return @($Xn, $Cn) } For ($k = 1;$k -le $Count;$k = $k + 1) { [Int64]$M = 4294967296 $New = MWC $Seed $Carry $Seed = $New[0] $Carry = $New[1] # Output seed from this iteration. '{0:n0}' -f $Seed # Alternate output statement for research. # " $k : Seed = " + '{0:n0}' -f $Seed + ", Carry = " + '{0:n0}' -f $Carry # Alternate output statement for normalized real numbers, greater or equal to 0 and less than 1. # '{0:n15}' -f ($Seed / $M) }