Compare commits
9 Commits
Author | SHA1 | Date | |
---|---|---|---|
9b3f3e593f | |||
02cf21f092 | |||
56f3a5ed3a | |||
06d7ff4586 | |||
33a838ff69 | |||
d1ea2c1406 | |||
d7a36afe0d | |||
88dc46f552 | |||
44698ca88e |
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
benfords-law
|
||||
benfords-law.exe
|
31
README.md
31
README.md
@ -27,5 +27,32 @@ $ ./benfords-law.exe
|
||||
Press 'Enter' to continue...
|
||||
```
|
||||
|
||||
This shows that Benford's law only works when the data is not random, such as natural data gathered in real life. This is because natural data is generated following a power law, which is common in nature.
|
||||
|
||||
This shows that Benford's law only works when the data is not random, such as natural data gathered in real life. This is because for data which Benford's law does work, it's natural data generated following a [power law](https://en.wikipedia.org/wiki/Power_law), which is quite common in nature.
|
||||
|
||||
### Run this program yourself
|
||||
|
||||
If you wish to run this program yourself, you can download it from the releases page for Windows or Linux. You can also build it yourself, instructions below:
|
||||
|
||||
### Build Prerequisites
|
||||
|
||||
You can have pretty much any mainstream Operating System or CPU architecture out there, but you need some buildtime dependancies on your system to move forward. You may already have these, you'll know if you do.
|
||||
|
||||
1. Install Go https://golang.org/, if you don't know what this is, yes that is a picture of a gopher on the home page but this is no joke.
|
||||
2. Install Git https://git-scm.com/downloads, this is version control software which is used to download this code to be available on your system sp you can run it yourself if you like.
|
||||
|
||||
### Build Instructions
|
||||
|
||||
From a command prompt / shell or whatever you got, clone this repository using git.
|
||||
|
||||
```shell
|
||||
git clone https://deadbeef.codes/steven/benfords-law.git
|
||||
```
|
||||
|
||||
Change directory into the downloaded local copy, then build the program using Go.
|
||||
|
||||
```shell
|
||||
cd benfords-law
|
||||
go build .
|
||||
```
|
||||
|
||||
You will be left with an executable file named benfords-law in the same directory.
|
||||
|
36
main.go
36
main.go
@ -7,25 +7,26 @@ import (
|
||||
"math"
|
||||
"math/rand"
|
||||
"os"
|
||||
"runtime"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
randomMin = 0
|
||||
randomMax = 9999999999999999
|
||||
numSamples = 10000000
|
||||
randomMin = 1 // We specify a range which random numbers will be generated, we must start at the first possible left-most digit
|
||||
randomMax = 999999999999999999 // int64 max value is 9223372036854775807. We use one digit less than that with all 9's in order to not give bias to any digits.
|
||||
numSamples = 100000000 // A nice rounded human number
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
results := [9]int{} // There are 9 possible leading digits and 0 does not count, offset by 1 for index to actual value. Examples: To access 1 use [0]. To access 5 use [4]. To access 9 use [8].
|
||||
currentSample := 0
|
||||
// In results, we store a count of each left most leading digits as numbers are randomly genereated
|
||||
results := [9]int{} // There are 9 possible leading digits and 0 does not count, offset by 1 for index to actual value. Examples: To access count for 1 use [0]. To access 5 use [4]. To access 9 use [8].
|
||||
currentSample := 0 // A counter that increments each time a random number sample has been generated. Used for status messages
|
||||
|
||||
// Start a little goroutine to output status and attach a ticker to execute it each second
|
||||
statusTicker := time.NewTicker(time.Second)
|
||||
go func() {
|
||||
for {
|
||||
<-statusTicker.C
|
||||
<-statusTicker.C // Wait for heartbeat from ticker channel
|
||||
percentCompleted := (currentSample * 100) / numSamples
|
||||
log.Printf("%d%% completed generating and analyzing samples", percentCompleted)
|
||||
}
|
||||
@ -34,33 +35,24 @@ func main() {
|
||||
log.Printf("generating numbers...")
|
||||
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
generatedNumbers := make(chan int, 1024)
|
||||
for i := 0; i < runtime.NumCPU(); i++ {
|
||||
go generatorWorker(generatedNumbers)
|
||||
}
|
||||
|
||||
for currentSample = 0; currentSample < numSamples; currentSample++ {
|
||||
results[firstDigit(<-generatedNumbers)-1]++
|
||||
results[firstDigit(rand.Intn(randomMax-randomMin+1)+randomMin)-1]++ // Generate a random number between randomMin and randomMax, get the first digit then increment the counter in results array, remember, it's offset by 1
|
||||
}
|
||||
|
||||
// Done generating and counting digits, stop the status ticker
|
||||
statusTicker.Stop()
|
||||
log.Printf("done.")
|
||||
|
||||
// output results
|
||||
for digitMinusOne, count := range results {
|
||||
fmt.Printf("%d: %d (%f%%)\n", digitMinusOne+1, count, float64(count*100)/float64(numSamples))
|
||||
// Output results
|
||||
for digitMinusOne, digitCount := range results {
|
||||
fmt.Printf("%d: %d (%f%%)\n", digitMinusOne+1, digitCount, float64(digitCount*100)/float64(numSamples))
|
||||
}
|
||||
|
||||
// Wait indefinitely until Enter Key is pressed, avoid terminating terminal before viewing results if ran from a shell
|
||||
fmt.Print("Press 'Enter' to continue...")
|
||||
bufio.NewReader(os.Stdin).ReadBytes('\n')
|
||||
}
|
||||
|
||||
func generatorWorker(returnChannel chan int) {
|
||||
for {
|
||||
returnChannel <- rand.Intn(randomMax-randomMin+1) + randomMin // We must use Intn instead of Int because from Base10's perspective, integers cut off at a really weird spot
|
||||
}
|
||||
}
|
||||
|
||||
// firstDigit returns the first/leftmost digit of the base10 representation of an integer
|
||||
func firstDigit(x int) int {
|
||||
return int(math.Abs(float64(x)) / math.Pow(10, float64(numDigits(x)-1)))
|
||||
|
Loading…
Reference in New Issue
Block a user