Browse Source

Change algorithm to work on 64-bit integers rather than 32-bit integers internally

gingerBill 2 years ago
parent
commit
d13bed9a0a

+ 19 - 122
core/math/rand/rand.odin

@@ -1,3 +1,4 @@
+
 /*
 /*
 Package core:math/rand implements various random number generators
 Package core:math/rand implements various random number generators
 */
 */
@@ -31,10 +32,6 @@ Example:
 		fmt.println(rand.uint64())
 		fmt.println(rand.uint64())
 	}
 	}
 
 
-Possible Output:
-
-	10
-
 */
 */
 set_global_seed :: proc(seed: u64) {
 set_global_seed :: proc(seed: u64) {
 	init(&global_rand, seed)
 	init(&global_rand, seed)
@@ -58,10 +55,6 @@ Example:
 		fmt.println(rand.uint64(&my_rand))
 		fmt.println(rand.uint64(&my_rand))
 	}
 	}
 
 
-Possible Output:
-
-	10
-
 */
 */
 @(require_results)
 @(require_results)
 create :: proc(seed: u64) -> (res: Rand) {
 create :: proc(seed: u64) -> (res: Rand) {
@@ -70,6 +63,7 @@ create :: proc(seed: u64) -> (res: Rand) {
 	return r
 	return r
 }
 }
 
 
+
 /*
 /*
 Initialises a random number generator.
 Initialises a random number generator.
 
 
@@ -87,17 +81,13 @@ Example:
 		fmt.println(rand.uint64(&my_rand))
 		fmt.println(rand.uint64(&my_rand))
 	}
 	}
 
 
-Possible Output:
-
-	10
-
 */
 */
 init :: proc(r: ^Rand, seed: u64) {
 init :: proc(r: ^Rand, seed: u64) {
 	r.state = 0
 	r.state = 0
 	r.inc = (seed << 1) | 1
 	r.inc = (seed << 1) | 1
-	_random(r)
+	_random_u64(r)
 	r.state += seed
 	r.state += seed
-	_random(r)
+	_random_u64(r)
 }
 }
 
 
 /*
 /*
@@ -123,11 +113,6 @@ Example:
 		rand.init_as_system(&my_rand)
 		rand.init_as_system(&my_rand)
 		fmt.println(rand.uint64(&my_rand))
 		fmt.println(rand.uint64(&my_rand))
 	}
 	}
-
-Possible Output:
-
-	10
-
 */
 */
 init_as_system :: proc(r: ^Rand) {
 init_as_system :: proc(r: ^Rand) {
 	if !#defined(_system_random) {
 	if !#defined(_system_random) {
@@ -139,11 +124,9 @@ init_as_system :: proc(r: ^Rand) {
 }
 }
 
 
 @(private)
 @(private)
-_random :: proc(r: ^Rand) -> u32 {
+_random_u64 :: proc(r: ^Rand) -> u64 {
 	r := r
 	r := r
 	if r == nil {
 	if r == nil {
-		// NOTE(bill, 2020-09-07): Do this so that people can
-		// enforce the global random state if necessary with `nil`
 		r = &global_rand
 		r = &global_rand
 	}
 	}
 	when #defined(_system_random) {
 	when #defined(_system_random) {
@@ -154,9 +137,9 @@ _random :: proc(r: ^Rand) -> u32 {
 
 
 	old_state := r.state
 	old_state := r.state
 	r.state = old_state * 6364136223846793005 + (r.inc|1)
 	r.state = old_state * 6364136223846793005 + (r.inc|1)
-	xor_shifted := u32(((old_state>>18) ~ old_state) >> 27)
-	rot := u32(old_state >> 59)
-	return (xor_shifted >> rot) | (xor_shifted << ((-rot) & 31))
+	word := (((old_state >> 59) + 5) ~ old_state) * 12605985483714917081
+	rot := (word >> 43) ~ word
+	return (word >> rot) | (word << ((-rot) & 63))
 }
 }
 
 
 /*
 /*
@@ -179,15 +162,9 @@ Example:
 		my_rand := rand.create(1)
 		my_rand := rand.create(1)
 		fmt.println(rand.uint32(&my_rand))
 		fmt.println(rand.uint32(&my_rand))
 	}
 	}
-
-Possible Output:
-
-	10
-	389
-
 */
 */
 @(require_results)
 @(require_results)
-uint32 :: proc(r: ^Rand = nil) -> (val: u32) { return _random(r) }
+uint32 :: proc(r: ^Rand = nil) -> (val: u32) { return u32(_random_u64(r)) }
 
 
 /*
 /*
 Generates a random 64 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
 Generates a random 64 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
@@ -209,19 +186,9 @@ Example:
 		my_rand := rand.create(1)
 		my_rand := rand.create(1)
 		fmt.println(rand.uint64(&my_rand))
 		fmt.println(rand.uint64(&my_rand))
 	}
 	}
-
-Possible Output:
-
-	10
-	389
-
 */
 */
 @(require_results)
 @(require_results)
-uint64 :: proc(r: ^Rand = nil) -> (val: u64) {
-	a := u64(_random(r))
-	b := u64(_random(r))
-	return (a<<32) | b
-}
+uint64 :: proc(r: ^Rand = nil) -> (val: u64) { return _random_u64(r) }
 
 
 /*
 /*
 Generates a random 128 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
 Generates a random 128 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
@@ -243,20 +210,12 @@ Example:
 		my_rand := rand.create(1)
 		my_rand := rand.create(1)
 		fmt.println(rand.uint128(&my_rand))
 		fmt.println(rand.uint128(&my_rand))
 	}
 	}
-
-Possible Output:
-
-	10
-	389
-
 */
 */
 @(require_results)
 @(require_results)
 uint128 :: proc(r: ^Rand = nil) -> (val: u128) {
 uint128 :: proc(r: ^Rand = nil) -> (val: u128) {
-	a := u128(_random(r))
-	b := u128(_random(r))
-	c := u128(_random(r))
-	d := u128(_random(r))
-	return (a<<96) | (b<<64) | (c<<32) | d
+	a := u128(_random_u64(r))
+	b := u128(_random_u64(r))
+	return (a<<64) | b
 }
 }
 
 
 /*
 /*
@@ -280,14 +239,9 @@ Example:
 		my_rand := rand.create(1)
 		my_rand := rand.create(1)
 		fmt.println(rand.int31(&my_rand))
 		fmt.println(rand.int31(&my_rand))
 	}
 	}
-
-Possible Output:
-
-	10
-	389
-
 */
 */
 @(require_results) int31  :: proc(r: ^Rand = nil) -> (val: i32)  { return i32(uint32(r) << 1 >> 1) }
 @(require_results) int31  :: proc(r: ^Rand = nil) -> (val: i32)  { return i32(uint32(r) << 1 >> 1) }
+
 /*
 /*
 Generates a random 63 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.  
 Generates a random 63 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.  
 The sign bit will always be set to 0, thus all generated numbers will be positive.
 The sign bit will always be set to 0, thus all generated numbers will be positive.
@@ -309,14 +263,9 @@ Example:
 		my_rand := rand.create(1)
 		my_rand := rand.create(1)
 		fmt.println(rand.int63(&my_rand))
 		fmt.println(rand.int63(&my_rand))
 	}
 	}
-
-Possible Output:
-
-	10
-	389
-
 */
 */
 @(require_results) int63  :: proc(r: ^Rand = nil) -> (val: i64)  { return i64(uint64(r) << 1 >> 1) }
 @(require_results) int63  :: proc(r: ^Rand = nil) -> (val: i64)  { return i64(uint64(r) << 1 >> 1) }
+
 /*
 /*
 Generates a random 127 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.  
 Generates a random 127 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.  
 The sign bit will always be set to 0, thus all generated numbers will be positive.
 The sign bit will always be set to 0, thus all generated numbers will be positive.
@@ -338,12 +287,6 @@ Example:
 		my_rand := rand.create(1)
 		my_rand := rand.create(1)
 		fmt.println(rand.int127(&my_rand))
 		fmt.println(rand.int127(&my_rand))
 	}
 	}
-
-Possible Output:
-
-	10
-	389
-
 */
 */
 @(require_results) int127 :: proc(r: ^Rand = nil) -> (val: i128) { return i128(uint128(r) << 1 >> 1) }
 @(require_results) int127 :: proc(r: ^Rand = nil) -> (val: i128) { return i128(uint128(r) << 1 >> 1) }
 
 
@@ -370,12 +313,6 @@ Example:
 		my_rand := rand.create(1)
 		my_rand := rand.create(1)
 		fmt.println(rand.int31_max(1024, &my_rand))
 		fmt.println(rand.int31_max(1024, &my_rand))
 	}
 	}
-
-Possible Output:
-
-	6
-	500
-
 */
 */
 @(require_results)
 @(require_results)
 int31_max :: proc(n: i32, r: ^Rand = nil) -> (val: i32) {
 int31_max :: proc(n: i32, r: ^Rand = nil) -> (val: i32) {
@@ -392,6 +329,7 @@ int31_max :: proc(n: i32, r: ^Rand = nil) -> (val: i32) {
 	}
 	}
 	return v % n
 	return v % n
 }
 }
+
 /*
 /*
 Generates a random 63 bit value in the range `[0, n)` using the provided random number generator. If no generator is provided the global random number generator will be used.
 Generates a random 63 bit value in the range `[0, n)` using the provided random number generator. If no generator is provided the global random number generator will be used.
 
 
@@ -416,10 +354,6 @@ Example:
 		fmt.println(rand.int63_max(1024, &my_rand))
 		fmt.println(rand.int63_max(1024, &my_rand))
 	}
 	}
 
 
-Possible Output:
-
-	6
-	500
 
 
 */
 */
 @(require_results)
 @(require_results)
@@ -437,6 +371,7 @@ int63_max :: proc(n: i64, r: ^Rand = nil) -> (val: i64) {
 	}
 	}
 	return v % n
 	return v % n
 }
 }
+
 /*
 /*
 Generates a random 127 bit value in the range `[0, n)` using the provided random number generator. If no generator is provided the global random number generator will be used.
 Generates a random 127 bit value in the range `[0, n)` using the provided random number generator. If no generator is provided the global random number generator will be used.
 
 
@@ -461,10 +396,6 @@ Example:
 		fmt.println(rand.int127_max(1024, &my_rand))
 		fmt.println(rand.int127_max(1024, &my_rand))
 	}
 	}
 
 
-Possible Output:
-
-	6
-	500
 
 
 */
 */
 @(require_results)
 @(require_results)
@@ -482,6 +413,7 @@ int127_max :: proc(n: i128, r: ^Rand = nil) -> (val: i128) {
 	}
 	}
 	return v % n
 	return v % n
 }
 }
+
 /*
 /*
 Generates a random integer value in the range `[0, n)` using the provided random number generator. If no generator is provided the global random number generator will be used.
 Generates a random integer value in the range `[0, n)` using the provided random number generator. If no generator is provided the global random number generator will be used.
 
 
@@ -506,10 +438,6 @@ Example:
 		fmt.println(rand.int_max(1024, &my_rand))
 		fmt.println(rand.int_max(1024, &my_rand))
 	}
 	}
 
 
-Possible Output:
-
-	6
-	500
 
 
 */
 */
 @(require_results)
 @(require_results)
@@ -545,10 +473,6 @@ Example:
 		fmt.println(rand.float64(&my_rand))
 		fmt.println(rand.float64(&my_rand))
 	}
 	}
 
 
-Possible Output:
-
-	0.043
-	0.511
 
 
 */
 */
 @(require_results) float64 :: proc(r: ^Rand = nil) -> (val: f64) { return f64(int63_max(1<<53, r)) / (1 << 53) }
 @(require_results) float64 :: proc(r: ^Rand = nil) -> (val: f64) { return f64(int63_max(1<<53, r)) / (1 << 53) }
@@ -574,10 +498,6 @@ Example:
 		fmt.println(rand.float32(&my_rand))
 		fmt.println(rand.float32(&my_rand))
 	}
 	}
 
 
-Possible Output:
-
-	0.043
-	0.511
 
 
 */
 */
 @(require_results) float32 :: proc(r: ^Rand = nil) -> (val: f32) { return f32(float64(r)) }
 @(require_results) float32 :: proc(r: ^Rand = nil) -> (val: f32) { return f32(float64(r)) }
@@ -605,13 +525,10 @@ Example:
 		fmt.println(rand.float64_range(600, 900, &my_rand))
 		fmt.println(rand.float64_range(600, 900, &my_rand))
 	}
 	}
 
 
-Possible Output:
-
-	15.312
-	673.130
 
 
 */
 */
 @(require_results) float64_range :: proc(low, high: f64, r: ^Rand = nil) -> (val: f64) { return (high-low)*float64(r) + low }
 @(require_results) float64_range :: proc(low, high: f64, r: ^Rand = nil) -> (val: f64) { return (high-low)*float64(r) + low }
+
 /*
 /*
 Generates a random single floating point value in the range `(low, high]` using the provided random number generator. If no generator is provided the global random number generator will be used.  
 Generates a random single floating point value in the range `(low, high]` using the provided random number generator. If no generator is provided the global random number generator will be used.  
 
 
@@ -635,10 +552,6 @@ Example:
 		fmt.println(rand.float32_range(600, 900, &my_rand))
 		fmt.println(rand.float32_range(600, 900, &my_rand))
 	}
 	}
 
 
-Possible Output:
-
-	15.312
-	673.130
 
 
 */
 */
 @(require_results) float32_range :: proc(low, high: f32, r: ^Rand = nil) -> (val: f32) { return (high-low)*float32(r) + low }
 @(require_results) float32_range :: proc(low, high: f32, r: ^Rand = nil) -> (val: f32) { return (high-low)*float32(r) + low }
@@ -665,10 +578,6 @@ Example:
 		fmt.println(data)
 		fmt.println(data)
 	}
 	}
 
 
-Possible Output:
-
-	8
-	[32, 4, 59, 7, 1, 2, 2, 119]
 
 
 */
 */
 @(require_results)
 @(require_results)
@@ -720,10 +629,6 @@ Example:
 		return
 		return
 	}
 	}
 
 
-Possible Output:
-
-	[7201011, 3, 9123, 231131]
-	[19578, 910081, 131, 7]
 
 
 */
 */
 @(require_results)
 @(require_results)
@@ -756,10 +661,6 @@ Example:
 		fmt.println(data) // the contents have been shuffled
 		fmt.println(data) // the contents have been shuffled
 	}
 	}
 
 
-Possible Output:
-
-	[1, 2, 3, 4]
-	[2, 4, 3, 1]
 
 
 */
 */
 shuffle :: proc(array: $T/[]$E, r: ^Rand = nil) {
 shuffle :: proc(array: $T/[]$E, r: ^Rand = nil) {
@@ -798,10 +699,6 @@ Example:
 	}
 	}
 
 
 
 
-Possible Output:
-
-	3
-	2
 	2
 	2
 	4
 	4
 
 

+ 3 - 3
core/math/rand/system_darwin.odin

@@ -3,10 +3,10 @@ package rand
 import "core:sys/darwin"
 import "core:sys/darwin"
 
 
 @(require_results)
 @(require_results)
-_system_random :: proc() -> u32 {
+_system_random :: proc() -> u64 {
 	for {
 	for {
-		value: u32
-		ret := darwin.syscall_getentropy(([^]u8)(&value), 4)
+		value: u64
+		ret := darwin.syscall_getentropy(([^]u8)(&value), size_of(value))
 		if ret < 0 {
 		if ret < 0 {
 			switch ret {
 			switch ret {
 			case -4: // EINTR
 			case -4: // EINTR

+ 3 - 3
core/math/rand/system_linux.odin

@@ -3,10 +3,10 @@ package rand
 import "core:sys/unix"
 import "core:sys/unix"
 
 
 @(require_results)
 @(require_results)
-_system_random :: proc() -> u32 {
+_system_random :: proc() -> u64 {
 	for {
 	for {
-		value: u32
-		ret := unix.sys_getrandom(([^]u8)(&value), 4, 0)
+		value: u64
+		ret := unix.sys_getrandom(([^]u8)(&value), size_of(value), 0)
 		if ret < 0 {
 		if ret < 0 {
 			switch ret {
 			switch ret {
 			case -4: // EINTR
 			case -4: // EINTR

+ 3 - 3
core/math/rand/system_windows.odin

@@ -3,9 +3,9 @@ package rand
 import win32 "core:sys/windows"
 import win32 "core:sys/windows"
 
 
 @(require_results)
 @(require_results)
-_system_random :: proc() -> u32 {
-	value: u32
-	status := win32.BCryptGenRandom(nil, ([^]u8)(&value), 4, win32.BCRYPT_USE_SYSTEM_PREFERRED_RNG)
+_system_random :: proc() -> u64 {
+	value: u64
+	status := win32.BCryptGenRandom(nil, ([^]u8)(&value), size_of(value), win32.BCRYPT_USE_SYSTEM_PREFERRED_RNG)
 	if status < 0 {
 	if status < 0 {
 		panic("BCryptGenRandom failed")
 		panic("BCryptGenRandom failed")
 	}
 	}