From 13108776ae6a5cacdf5e3d402db8605dc465ac51 Mon Sep 17 00:00:00 2001 From: Peter Limkilde Svendsen Date: Wed, 22 May 2019 18:48:19 +0200 Subject: [PATCH 1/6] Implement erand48(), jrand48() and nrand48() --- src/header/stdlib/lcg48.rs | 26 ++++++++++++++++++++--- src/header/stdlib/mod.rs | 33 +++++++++++++++++++----------- tests/expected/stdlib/lcg48.stdout | 3 +++ tests/stdlib/lcg48.c | 25 ++++++++++++++++++++++ 4 files changed, 72 insertions(+), 15 deletions(-) diff --git a/src/header/stdlib/lcg48.rs b/src/header/stdlib/lcg48.rs index cba8188ca0..8763b72c28 100644 --- a/src/header/stdlib/lcg48.rs +++ b/src/header/stdlib/lcg48.rs @@ -12,14 +12,14 @@ pub static mut XI: u64 = 0; pub static mut A: u64 = 0x5deece66d; pub static mut C: u16 = 0xb; -/// Advances the linear congruential generator to the next element in its +/// Gets the next element in the linear congruential generator's /// sequence. -pub unsafe fn generator_step() { +pub unsafe fn next_x(x: u64) -> u64 { /* The recurrence relation of the linear congruential generator, * X_(n+1) = (a * X_n + c) % m, * with m = 2**48. The multiplication and addition can overflow a u64, but * we just let it wrap since we take mod 2**48 anyway. */ - XI = A.wrapping_mul(XI).wrapping_add(u64::from(C)) & 0xffff_ffff_ffff; + A.wrapping_mul(x).wrapping_add(u64::from(C)) & 0xffff_ffff_ffff } /// Get a C `double` from a 48-bit integer (for `drand48()` and `erand48()`). @@ -41,3 +41,23 @@ pub fn x_to_int32(x: u64) -> c_long { // Cast via i32 to ensure we get the sign correct (x >> 16) as i32 as c_long } + +/// Build a 48-bit integer from a size-3 array of unsigned short. +/// +/// Takes a pointer argument due to the inappropriate C function +/// signatures generated from Rust's sized arrays, see +/// https://github.com/eqrion/cbindgen/issues/171 +pub unsafe fn ushort_arr3_to_uint48(arr_ptr: *const c_ushort) -> u64 { + let arr = [*arr_ptr.offset(0), *arr_ptr.offset(1), *arr_ptr.offset(2)]; + + /* Cast via u16 to ensure we get only the lower 16 bits of each + * element, as specified by POSIX. */ + u64::from(arr[0] as u16) | (u64::from(arr[1] as u16) << 16) | (u64::from(arr[2] as u16) << 32) +} + +/// Set a size-3 array of unsigned short from a 48-bit integer. +pub unsafe fn set_ushort_arr3_from_uint48(arr_ptr: *mut c_ushort, value: u64) { + *arr_ptr.offset(0) = c_ushort::from(value as u16); + *arr_ptr.offset(1) = c_ushort::from((value >> 16) as u16); + *arr_ptr.offset(2) = c_ushort::from((value >> 32) as u16); +} diff --git a/src/header/stdlib/mod.rs b/src/header/stdlib/mod.rs index eb157f70fc..8189dcf4be 100644 --- a/src/header/stdlib/mod.rs +++ b/src/header/stdlib/mod.rs @@ -232,7 +232,7 @@ pub extern "C" fn div(numer: c_int, denom: c_int) -> div_t { #[no_mangle] pub unsafe extern "C" fn drand48() -> c_double { - lcg48::generator_step(); + lcg48::XI = lcg48::next_x(lcg48::XI); lcg48::x_to_float64(lcg48::XI) } @@ -246,9 +246,12 @@ pub extern "C" fn ecvt( unimplemented!(); } -// #[no_mangle] -pub extern "C" fn erand(xsubi: [c_ushort; 3]) -> c_double { - unimplemented!(); +#[no_mangle] +pub unsafe extern "C" fn erand48(xsubi: *mut c_ushort) -> c_double { + let old_xi = lcg48::ushort_arr3_to_uint48(xsubi); + let new_xi = lcg48::next_x(old_xi); + lcg48::set_ushort_arr3_from_uint48(xsubi, new_xi); + lcg48::x_to_float64(new_xi) } #[no_mangle] @@ -361,9 +364,12 @@ pub extern "C" fn initstate(seec: c_uint, state: *mut c_char, size: size_t) -> * unimplemented!(); } -// #[no_mangle] -pub extern "C" fn jrand48(xsubi: [c_ushort; 3]) -> c_long { - unimplemented!(); +#[no_mangle] +pub unsafe extern "C" fn jrand48(xsubi: *mut c_ushort) -> c_long { + let old_xi = lcg48::ushort_arr3_to_uint48(xsubi); + let new_xi = lcg48::next_x(old_xi); + lcg48::set_ushort_arr3_from_uint48(xsubi, new_xi); + lcg48::x_to_int32(new_xi) } // #[no_mangle] @@ -416,7 +422,7 @@ pub extern "C" fn lldiv(numer: c_longlong, denom: c_longlong) -> lldiv_t { #[no_mangle] pub unsafe extern "C" fn lrand48() -> c_long { - lcg48::generator_step(); + lcg48::XI = lcg48::next_x(lcg48::XI); lcg48::x_to_uint31(lcg48::XI) } @@ -573,13 +579,16 @@ pub extern "C" fn mkstemps(name: *mut c_char, suffix_len: c_int) -> c_int { #[no_mangle] pub unsafe extern "C" fn mrand48() -> c_long { - lcg48::generator_step(); + lcg48::XI = lcg48::next_x(lcg48::XI); lcg48::x_to_int32(lcg48::XI) } -// #[no_mangle] -pub extern "C" fn nrand48(xsubi: [c_ushort; 3]) -> c_long { - unimplemented!(); +#[no_mangle] +pub unsafe extern "C" fn nrand48(xsubi: *mut c_ushort) -> c_long { + let old_xi = lcg48::ushort_arr3_to_uint48(xsubi); + let new_xi = lcg48::next_x(old_xi); + lcg48::set_ushort_arr3_from_uint48(xsubi, new_xi); + lcg48::x_to_uint31(new_xi) } // #[no_mangle] diff --git a/tests/expected/stdlib/lcg48.stdout b/tests/expected/stdlib/lcg48.stdout index 14522ff60b..40d35e82f4 100644 --- a/tests/expected/stdlib/lcg48.stdout +++ b/tests/expected/stdlib/lcg48.stdout @@ -2,3 +2,6 @@ lrand48 (uninitialized): 0 2116118 89401895 379337186 782977366 196130996 198207 drand48: 0.750266 0.607593 0.567593 0.799563 0.984984 0.205670 0.625922 0.794426 0.369416 0.854100 lrand48: 1611183183 1304796356 1218897288 1717049088 2115236938 441672110 1344158015 1706017430 793314380 1834165927 mrand48: -1072600929 -1685374584 -1857172720 -860869119 -64493420 883344220 -1606651266 -882932436 1586628760 -626635441 +erand48: 0.210555 0.014158 0.111353 0.658369 0.103767 0.180385 0.945033 0.745768 0.290272 0.111716 +nrand48: 514983590 590935818 1480794144 1496813112 2133865028 1816766485 2095074020 126058208 909762120 14734916 +jrand48: -1066398599 903693914 -1922375113 -2090140830 1218074962 1662411059 -722435322 764426686 -874142666 -1454656015 diff --git a/tests/stdlib/lcg48.c b/tests/stdlib/lcg48.c index da8c76a46a..1d87589e4a 100644 --- a/tests/stdlib/lcg48.c +++ b/tests/stdlib/lcg48.c @@ -7,6 +7,7 @@ int main(void) { long x_l, x_m; double x_d; long seedval = 0xcafebeef; + unsigned short xsubi[3] = {0xabcd, 0xef42, 0x5678}; printf("lrand48 (uninitialized):"); for (int i = 0; i < 10; i++) @@ -42,4 +43,28 @@ int main(void) { printf(" %ld", x_m); } printf("\n"); + + printf("erand48:"); + for (int i = 0; i < 10; i++) + { + x_d = erand48(xsubi); + printf(" %lf", x_d); + } + printf("\n"); + + printf("nrand48:"); + for (int i = 0; i < 10; i++) + { + x_l = nrand48(xsubi); + printf(" %ld", x_l); + } + printf("\n"); + + printf("jrand48:"); + for (int i = 0; i < 10; i++) + { + x_l = jrand48(xsubi); + printf(" %ld", x_l); + } + printf("\n"); } From 767cf86b382516239e9ea18687d1b06ef40c738a Mon Sep 17 00:00:00 2001 From: Peter Limkilde Svendsen Date: Wed, 22 May 2019 21:09:26 +0200 Subject: [PATCH 2/6] Refer to newer standard (with correct half-open output intervals) --- src/header/stdlib/lcg48.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/header/stdlib/lcg48.rs b/src/header/stdlib/lcg48.rs index 8763b72c28..4963d4fddb 100644 --- a/src/header/stdlib/lcg48.rs +++ b/src/header/stdlib/lcg48.rs @@ -1,4 +1,4 @@ -//! Helper functions for pseudorandom number generation using LCG, see http://pubs.opengroup.org/onlinepubs/7908799/xsh/drand48.html +//! Helper functions for pseudorandom number generation using LCG, see https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/functions/drand48.html use platform::types::*; From b2a9cdf930b605bf767852e193f40e25c154ec7e Mon Sep 17 00:00:00 2001 From: Peter Limkilde Svendsen Date: Thu, 23 May 2019 20:36:13 +0200 Subject: [PATCH 3/6] Implement lcong48() and seed48() --- src/header/stdlib/lcg48.rs | 16 ++++++- src/header/stdlib/mod.rs | 27 ++++++++--- tests/expected/stdlib/lcg48.stdout | 13 ++++-- tests/stdlib/lcg48.c | 73 ++++++++++++++++++++++++++++-- 4 files changed, 114 insertions(+), 15 deletions(-) diff --git a/src/header/stdlib/lcg48.rs b/src/header/stdlib/lcg48.rs index 4963d4fddb..a847f742bb 100644 --- a/src/header/stdlib/lcg48.rs +++ b/src/header/stdlib/lcg48.rs @@ -7,10 +7,16 @@ use platform::types::*; * set. */ pub static mut XI: u64 = 0; +// Used by seed48() (returns a pointer to this array). +pub static mut STASHED_XI: [c_ushort; 3] = [0; 3]; + /* Multiplier and addend, which may be set through lcong48(). Default values as * specified in POSIX. */ -pub static mut A: u64 = 0x5deece66d; -pub static mut C: u16 = 0xb; +const A_DEFAULT: u64 = 0x5deece66d; +const C_DEFAULT: u16 = 0xb; + +pub static mut A: u64 = A_DEFAULT; +pub static mut C: u16 = C_DEFAULT; /// Gets the next element in the linear congruential generator's /// sequence. @@ -61,3 +67,9 @@ pub unsafe fn set_ushort_arr3_from_uint48(arr_ptr: *mut c_ushort, value: u64) { *arr_ptr.offset(1) = c_ushort::from((value >> 16) as u16); *arr_ptr.offset(2) = c_ushort::from((value >> 32) as u16); } + +/// Used by `srand48()` and `seed48()`. +pub unsafe fn reset_a_and_c() { + A = A_DEFAULT; + C = C_DEFAULT; +} diff --git a/src/header/stdlib/mod.rs b/src/header/stdlib/mod.rs index 8189dcf4be..cb64ae223d 100644 --- a/src/header/stdlib/mod.rs +++ b/src/header/stdlib/mod.rs @@ -382,9 +382,12 @@ pub extern "C" fn labs(i: c_long) -> c_long { i.abs() } -// #[no_mangle] -pub extern "C" fn lcong48(param: [c_ushort; 7]) { - unimplemented!(); +#[no_mangle] +pub unsafe extern "C" fn lcong48(param: *mut c_ushort) { + // Input should be a size-7 array. + lcg48::XI = lcg48::ushort_arr3_to_uint48(param.offset(0)); + lcg48::A = lcg48::ushort_arr3_to_uint48(param.offset(3)); + lcg48::C = *param.offset(6) as u16; // c_ushort may be more than 16 bits } #[repr(C)] @@ -703,9 +706,17 @@ pub unsafe extern "C" fn realpath(pathname: *const c_char, resolved: *mut c_char ptr } -// #[no_mangle] -pub extern "C" fn seed48(seed16v: [c_ushort; 3]) -> c_ushort { - unimplemented!(); +#[no_mangle] +pub unsafe extern "C" fn seed48(seed16v: *mut c_ushort) -> *mut c_ushort { + lcg48::reset_a_and_c(); + + //lcg48::STASHED_XI = lcg48::XI; + //lcg48::set_ushort_arr3_from_uint48(&mut lcg48::STASHED_XI[0] as *mut c_ushort, lcg48::XI); + lcg48::set_ushort_arr3_from_uint48(lcg48::STASHED_XI.as_mut_ptr(), lcg48::XI); + lcg48::XI = lcg48::ushort_arr3_to_uint48(seed16v); + + //&mut lcg48::STASHED_XI[0] + lcg48::STASHED_XI.as_mut_ptr() } #[no_mangle] @@ -792,10 +803,12 @@ pub unsafe extern "C" fn srand(seed: c_uint) { #[no_mangle] pub unsafe extern "C" fn srand48(seedval: c_long) { + lcg48::reset_a_and_c(); + /* Set the high 32 bits of the 48-bit X_i value to the lower 32 bits * of the input argument, and the lower 16 bits to 0x330e, as * specified in POSIX. */ - lcg48::XI = (((seedval & 0xffff_ffff) as u64) << 16) | 0x330e_u64; + lcg48::XI = (((seedval as u32) as u64) << 16) | 0x330e_u64; } // #[no_mangle] diff --git a/tests/expected/stdlib/lcg48.stdout b/tests/expected/stdlib/lcg48.stdout index 40d35e82f4..fa871030ba 100644 --- a/tests/expected/stdlib/lcg48.stdout +++ b/tests/expected/stdlib/lcg48.stdout @@ -1,7 +1,14 @@ lrand48 (uninitialized): 0 2116118 89401895 379337186 782977366 196130996 198207689 1046291021 1131187612 975888346 -drand48: 0.750266 0.607593 0.567593 0.799563 0.984984 0.205670 0.625922 0.794426 0.369416 0.854100 -lrand48: 1611183183 1304796356 1218897288 1717049088 2115236938 441672110 1344158015 1706017430 793314380 1834165927 -mrand48: -1072600929 -1685374584 -1857172720 -860869119 -64493420 883344220 -1606651266 -882932436 1586628760 -626635441 +drand48 (seeded with srand48): 0.750266 0.607593 0.567593 0.799563 0.984984 0.205670 0.625922 0.794426 0.369416 0.854100 +lrand48 (seeded with srand48): 1611183183 1304796356 1218897288 1717049088 2115236938 441672110 1344158015 1706017430 793314380 1834165927 +mrand48 (seeded with srand48): -1072600929 -1685374584 -1857172720 -860869119 -64493420 883344220 -1606651266 -882932436 1586628760 -626635441 erand48: 0.210555 0.014158 0.111353 0.658369 0.103767 0.180385 0.945033 0.745768 0.290272 0.111716 nrand48: 514983590 590935818 1480794144 1496813112 2133865028 1816766485 2095074020 126058208 909762120 14734916 jrand48: -1066398599 903693914 -1922375113 -2090140830 1218074962 1662411059 -722435322 764426686 -874142666 -1454656015 +seed48_return: [40c0, 4d4f, daa6] +lrand48 (seeded with seed48): 386486647 2049879217 706208537 1265096744 1586830881 1884641178 1566935266 1256810805 875501172 1670187935 +xsubi restored froom seed48 return value: [40c0, 4d4f, daa6] +nrand48 (from xsubi value returned by seed48): 1654466549 509433115 2007628085 1022767111 1935848687 967444157 1967758021 686622820 989863078 1688030308 +lrand48 (with parameters from lcong48): 2015972364 2009368981 971134301 317520085 149004773 538917235 242519436 1066970146 991527304 1588277058 +lrand48 (seeded with srand48 after lcong48 call): 1611183183 1304796356 1218897288 1717049088 2115236938 441672110 1344158015 1706017430 793314380 1834165927 +lrand48 (seeded with seed48 after lcong48 call): 386486647 2049879217 706208537 1265096744 1586830881 1884641178 1566935266 1256810805 875501172 1670187935 diff --git a/tests/stdlib/lcg48.c b/tests/stdlib/lcg48.c index 1d87589e4a..a1685f27fd 100644 --- a/tests/stdlib/lcg48.c +++ b/tests/stdlib/lcg48.c @@ -7,8 +7,12 @@ int main(void) { long x_l, x_m; double x_d; long seedval = 0xcafebeef; + unsigned short seed[3] = {0xfedc, 0xba98, 0x7654}; unsigned short xsubi[3] = {0xabcd, 0xef42, 0x5678}; + unsigned short lcong48_params[7] = {0x0123, 0x4567, 0x89ab, 0xcdef, 0x4242, 0xf000, 0xbaaa}; + unsigned short xsubi_from_seed48[3] = {0, 0, 0}; + /* Test uninitialized behavior */ printf("lrand48 (uninitialized):"); for (int i = 0; i < 10; i++) { @@ -17,8 +21,10 @@ int main(void) { } printf("\n"); + /* Test different output types with same seed, builtin X_i and + * default multiplier and addend */ srand48(seedval); - printf("drand48:"); + printf("drand48 (seeded with srand48):"); for (int i = 0; i < 10; i++) { x_d = drand48(); @@ -27,7 +33,7 @@ int main(void) { printf("\n"); srand48(seedval); - printf("lrand48:"); + printf("lrand48 (seeded with srand48):"); for (int i = 0; i < 10; i++) { x_l = lrand48(); @@ -36,7 +42,7 @@ int main(void) { printf("\n"); srand48(seedval); - printf("mrand48:"); + printf("mrand48 (seeded with srand48):"); for (int i = 0; i < 10; i++) { x_m = mrand48(); @@ -44,6 +50,8 @@ int main(void) { } printf("\n"); + /* Test corresponding functions taking user-supplied X_i, with + * default multiplier and addend */ printf("erand48:"); for (int i = 0; i < 10; i++) { @@ -67,4 +75,63 @@ int main(void) { printf(" %ld", x_l); } printf("\n"); + + /* Test seed48() "stashing" behavior. */ + unsigned short *seed48_return = seed48(seed); + printf("seed48_return: [%x, %x, %x]\n", + seed48_return[0], seed48_return[1], seed48_return[2]); + + /* Test seeding behavior of seed48() */ + printf("lrand48 (seeded with seed48):"); + for (int i = 0; i < 10; i++) + { + x_l = lrand48(); + printf(" %ld", x_l); + } + printf("\n"); + + /* Test restore from seed48()'s "stashed" value */ + xsubi_from_seed48[0] = seed48_return[0]; + xsubi_from_seed48[1] = seed48_return[1]; + xsubi_from_seed48[2] = seed48_return[2]; + printf("xsubi restored froom seed48 return value: [%x, %x, %x]\n", + xsubi_from_seed48[0], xsubi_from_seed48[1], xsubi_from_seed48[2]); + printf("nrand48 (from xsubi value returned by seed48):"); + for (int i = 0; i < 10; i++) + { + x_l = nrand48(xsubi_from_seed48); + printf(" %ld", x_l); + } + printf("\n"); + + /* Test behavior with all-user-defined parameters */ + lcong48(lcong48_params); + printf("lrand48 (with parameters from lcong48):"); + for (int i = 0; i < 10; i++) + { + x_l = lrand48(); + printf(" %ld", x_l); + } + printf("\n"); + + /* Test multiplier- and addend-restoring behavior of srand48() */ + srand48(seedval); + printf("lrand48 (seeded with srand48 after lcong48 call):"); + for (int i = 0; i < 10; i++) + { + x_l = lrand48(); + printf(" %ld", x_l); + } + printf("\n"); + + /* Test multiplier- and addend-restoring behavior of seed48() */ + lcong48(lcong48_params); + seed48(seed); + printf("lrand48 (seeded with seed48 after lcong48 call):"); + for (int i = 0; i < 10; i++) + { + x_l = lrand48(); + printf(" %ld", x_l); + } + printf("\n"); } From fe4a3ae2b4941785f6e1ff730f92b8c9403dc1c5 Mon Sep 17 00:00:00 2001 From: Peter Limkilde Svendsen Date: Thu, 23 May 2019 21:33:20 +0200 Subject: [PATCH 4/6] Refactor for consistency --- src/header/stdlib/lcg48.rs | 95 +++++++++++++++++++++----------------- src/header/stdlib/mod.rs | 42 ++++++++--------- 2 files changed, 73 insertions(+), 64 deletions(-) diff --git a/src/header/stdlib/lcg48.rs b/src/header/stdlib/lcg48.rs index a847f742bb..470d1f37fd 100644 --- a/src/header/stdlib/lcg48.rs +++ b/src/header/stdlib/lcg48.rs @@ -2,50 +2,27 @@ use platform::types::*; -/* The current element of the linear congruential generator's sequence. Any - * function that sets this variable must ensure that only the lower 48 bits get - * set. */ -pub static mut XI: u64 = 0; +/* The default element buffer for the linear congruential generator's + * sequence. Implemented using a c_ushort array for consistency between + * the drand48()/lrand48()/mrand48() and erand48()/nrand48()/jrand48() + * functions, and with STASHED_XI (see below). */ +pub static mut DEFAULT_XI: [c_ushort; 3] = [0; 3]; // Used by seed48() (returns a pointer to this array). pub static mut STASHED_XI: [c_ushort; 3] = [0; 3]; -/* Multiplier and addend, which may be set through lcong48(). Default values as - * specified in POSIX. */ -const A_DEFAULT: u64 = 0x5deece66d; -const C_DEFAULT: u16 = 0xb; +/* Multiplier and addend, which may be set through lcong48(). Default + * values as specified in POSIX. */ +const A_DEFAULT_VALUE: u64 = 0x5deece66d; +const C_DEFAULT_VALUE: u16 = 0xb; -pub static mut A: u64 = A_DEFAULT; -pub static mut C: u16 = C_DEFAULT; +pub static mut A: u64 = A_DEFAULT_VALUE; +pub static mut C: u16 = C_DEFAULT_VALUE; -/// Gets the next element in the linear congruential generator's -/// sequence. -pub unsafe fn next_x(x: u64) -> u64 { - /* The recurrence relation of the linear congruential generator, - * X_(n+1) = (a * X_n + c) % m, - * with m = 2**48. The multiplication and addition can overflow a u64, but - * we just let it wrap since we take mod 2**48 anyway. */ - A.wrapping_mul(x).wrapping_add(u64::from(C)) & 0xffff_ffff_ffff -} - -/// Get a C `double` from a 48-bit integer (for `drand48()` and `erand48()`). -pub fn x_to_float64(x: u64) -> c_double { - /* We set the exponent to 0, and the 48-bit integer is copied into the high - * 48 of the 52 significand bits. The value then lies in the range - * [1.0, 2.0), from which we simply subtract 1.0. */ - f64::from_bits(0x3ff0_0000_0000_0000_u64 | (x << 4)) - 1.0f64 -} - -/// Get the high 31 bits of a 48-bit integer (for `lrand48()` and `nrand48()`). -pub fn x_to_uint31(x: u64) -> c_long { - (x >> 17) as c_long -} - -/// Get the high 32 bits, signed, of a 48-bit integer (for `mrand48()` and -/// `jrand48()`). -pub fn x_to_int32(x: u64) -> c_long { - // Cast via i32 to ensure we get the sign correct - (x >> 16) as i32 as c_long +/// Used by `srand48()` and `seed48()`. +pub unsafe fn reset_a_and_c() { + A = A_DEFAULT_VALUE; + C = C_DEFAULT_VALUE; } /// Build a 48-bit integer from a size-3 array of unsigned short. @@ -68,8 +45,42 @@ pub unsafe fn set_ushort_arr3_from_uint48(arr_ptr: *mut c_ushort, value: u64) { *arr_ptr.offset(2) = c_ushort::from((value >> 32) as u16); } -/// Used by `srand48()` and `seed48()`. -pub unsafe fn reset_a_and_c() { - A = A_DEFAULT; - C = C_DEFAULT; +/// Advances the buffer from the input argument to the next element in +/// the linear congruential generator's sequence. +/// +/// Modifies the passed argument in-place and returns the new value as a +/// u64. The input argument must be a size-3 array. +pub unsafe fn generator_step(xi_arr_ptr: *mut c_ushort) -> u64 { + let old_xi: u64 = ushort_arr3_to_uint48(xi_arr_ptr); + + /* The recurrence relation of the linear congruential generator, + * X_(n+1) = (a * X_n + c) % m, + * with m = 2**48. The multiplication and addition can overflow a + * u64, but we just let it wrap since we take mod 2**48 anyway. */ + let new_xi: u64 = A.wrapping_mul(old_xi).wrapping_add(u64::from(C)) & 0xffff_ffff_ffff; + + set_ushort_arr3_from_uint48(xi_arr_ptr, new_xi); + new_xi +} + +/// Get a C `double` from a 48-bit integer (for `drand48()` and +/// `erand48()`). +pub fn x_to_float64(x: u64) -> c_double { + /* We set the exponent to 0, and the 48-bit integer is copied into the high + * 48 of the 52 significand bits. The value then lies in the range + * [1.0, 2.0), from which we simply subtract 1.0. */ + f64::from_bits(0x3ff0_0000_0000_0000_u64 | (x << 4)) - 1.0f64 +} + +/// Get the high 31 bits of a 48-bit integer (for `lrand48()` and +/// `nrand48()`). +pub fn x_to_uint31(x: u64) -> c_long { + (x >> 17) as c_long +} + +/// Get the high 32 bits, signed, of a 48-bit integer (for `mrand48()` +/// and `jrand48()`). +pub fn x_to_int32(x: u64) -> c_long { + // Cast via i32 to ensure we get the sign correct + c_long::from((x >> 16) as i32) } diff --git a/src/header/stdlib/mod.rs b/src/header/stdlib/mod.rs index cb64ae223d..995ce5b2a8 100644 --- a/src/header/stdlib/mod.rs +++ b/src/header/stdlib/mod.rs @@ -232,8 +232,8 @@ pub extern "C" fn div(numer: c_int, denom: c_int) -> div_t { #[no_mangle] pub unsafe extern "C" fn drand48() -> c_double { - lcg48::XI = lcg48::next_x(lcg48::XI); - lcg48::x_to_float64(lcg48::XI) + let new_xi = lcg48::generator_step(lcg48::DEFAULT_XI.as_mut_ptr()); + lcg48::x_to_float64(new_xi) } // #[no_mangle] @@ -248,9 +248,7 @@ pub extern "C" fn ecvt( #[no_mangle] pub unsafe extern "C" fn erand48(xsubi: *mut c_ushort) -> c_double { - let old_xi = lcg48::ushort_arr3_to_uint48(xsubi); - let new_xi = lcg48::next_x(old_xi); - lcg48::set_ushort_arr3_from_uint48(xsubi, new_xi); + let new_xi = lcg48::generator_step(xsubi); lcg48::x_to_float64(new_xi) } @@ -366,9 +364,7 @@ pub extern "C" fn initstate(seec: c_uint, state: *mut c_char, size: size_t) -> * #[no_mangle] pub unsafe extern "C" fn jrand48(xsubi: *mut c_ushort) -> c_long { - let old_xi = lcg48::ushort_arr3_to_uint48(xsubi); - let new_xi = lcg48::next_x(old_xi); - lcg48::set_ushort_arr3_from_uint48(xsubi, new_xi); + let new_xi = lcg48::generator_step(xsubi); lcg48::x_to_int32(new_xi) } @@ -385,7 +381,11 @@ pub extern "C" fn labs(i: c_long) -> c_long { #[no_mangle] pub unsafe extern "C" fn lcong48(param: *mut c_ushort) { // Input should be a size-7 array. - lcg48::XI = lcg48::ushort_arr3_to_uint48(param.offset(0)); + + /* Go through this ptr -> u64 -> ptr conversion to ensure we only + * get the lower 16 bits of each element. */ + let new_xi = lcg48::ushort_arr3_to_uint48(param.offset(0)); + lcg48::set_ushort_arr3_from_uint48(lcg48::DEFAULT_XI.as_mut_ptr(), new_xi); lcg48::A = lcg48::ushort_arr3_to_uint48(param.offset(3)); lcg48::C = *param.offset(6) as u16; // c_ushort may be more than 16 bits } @@ -425,8 +425,8 @@ pub extern "C" fn lldiv(numer: c_longlong, denom: c_longlong) -> lldiv_t { #[no_mangle] pub unsafe extern "C" fn lrand48() -> c_long { - lcg48::XI = lcg48::next_x(lcg48::XI); - lcg48::x_to_uint31(lcg48::XI) + let new_xi = lcg48::generator_step(lcg48::DEFAULT_XI.as_mut_ptr()); + lcg48::x_to_uint31(new_xi) } #[no_mangle] @@ -582,15 +582,13 @@ pub extern "C" fn mkstemps(name: *mut c_char, suffix_len: c_int) -> c_int { #[no_mangle] pub unsafe extern "C" fn mrand48() -> c_long { - lcg48::XI = lcg48::next_x(lcg48::XI); - lcg48::x_to_int32(lcg48::XI) + let new_xi = lcg48::generator_step(lcg48::DEFAULT_XI.as_mut_ptr()); + lcg48::x_to_int32(new_xi) } #[no_mangle] pub unsafe extern "C" fn nrand48(xsubi: *mut c_ushort) -> c_long { - let old_xi = lcg48::ushort_arr3_to_uint48(xsubi); - let new_xi = lcg48::next_x(old_xi); - lcg48::set_ushort_arr3_from_uint48(xsubi, new_xi); + let new_xi = lcg48::generator_step(xsubi); lcg48::x_to_uint31(new_xi) } @@ -710,12 +708,11 @@ pub unsafe extern "C" fn realpath(pathname: *const c_char, resolved: *mut c_char pub unsafe extern "C" fn seed48(seed16v: *mut c_ushort) -> *mut c_ushort { lcg48::reset_a_and_c(); - //lcg48::STASHED_XI = lcg48::XI; - //lcg48::set_ushort_arr3_from_uint48(&mut lcg48::STASHED_XI[0] as *mut c_ushort, lcg48::XI); - lcg48::set_ushort_arr3_from_uint48(lcg48::STASHED_XI.as_mut_ptr(), lcg48::XI); - lcg48::XI = lcg48::ushort_arr3_to_uint48(seed16v); + lcg48::STASHED_XI = lcg48::DEFAULT_XI; + + let new_xi = lcg48::ushort_arr3_to_uint48(seed16v); + lcg48::set_ushort_arr3_from_uint48(lcg48::DEFAULT_XI.as_mut_ptr(), new_xi); - //&mut lcg48::STASHED_XI[0] lcg48::STASHED_XI.as_mut_ptr() } @@ -808,7 +805,8 @@ pub unsafe extern "C" fn srand48(seedval: c_long) { /* Set the high 32 bits of the 48-bit X_i value to the lower 32 bits * of the input argument, and the lower 16 bits to 0x330e, as * specified in POSIX. */ - lcg48::XI = (((seedval as u32) as u64) << 16) | 0x330e_u64; + let new_xi = (((seedval as u32) as u64) << 16) | 0x330e_u64; + lcg48::set_ushort_arr3_from_uint48(lcg48::DEFAULT_XI.as_mut_ptr(), new_xi); } // #[no_mangle] From dcff3fd83633b58a721bddb6abb2a93fe163a45b Mon Sep 17 00:00:00 2001 From: Peter Limkilde Svendsen Date: Thu, 23 May 2019 21:40:06 +0200 Subject: [PATCH 5/6] Use y_from_x naming for functions --- src/header/stdlib/lcg48.rs | 10 +++++----- src/header/stdlib/mod.rs | 18 +++++++++--------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/header/stdlib/lcg48.rs b/src/header/stdlib/lcg48.rs index 470d1f37fd..84bfd45c01 100644 --- a/src/header/stdlib/lcg48.rs +++ b/src/header/stdlib/lcg48.rs @@ -30,7 +30,7 @@ pub unsafe fn reset_a_and_c() { /// Takes a pointer argument due to the inappropriate C function /// signatures generated from Rust's sized arrays, see /// https://github.com/eqrion/cbindgen/issues/171 -pub unsafe fn ushort_arr3_to_uint48(arr_ptr: *const c_ushort) -> u64 { +pub unsafe fn uint48_from_ushort_arr3(arr_ptr: *const c_ushort) -> u64 { let arr = [*arr_ptr.offset(0), *arr_ptr.offset(1), *arr_ptr.offset(2)]; /* Cast via u16 to ensure we get only the lower 16 bits of each @@ -51,7 +51,7 @@ pub unsafe fn set_ushort_arr3_from_uint48(arr_ptr: *mut c_ushort, value: u64) { /// Modifies the passed argument in-place and returns the new value as a /// u64. The input argument must be a size-3 array. pub unsafe fn generator_step(xi_arr_ptr: *mut c_ushort) -> u64 { - let old_xi: u64 = ushort_arr3_to_uint48(xi_arr_ptr); + let old_xi: u64 = uint48_from_ushort_arr3(xi_arr_ptr); /* The recurrence relation of the linear congruential generator, * X_(n+1) = (a * X_n + c) % m, @@ -65,7 +65,7 @@ pub unsafe fn generator_step(xi_arr_ptr: *mut c_ushort) -> u64 { /// Get a C `double` from a 48-bit integer (for `drand48()` and /// `erand48()`). -pub fn x_to_float64(x: u64) -> c_double { +pub fn float64_from_x(x: u64) -> c_double { /* We set the exponent to 0, and the 48-bit integer is copied into the high * 48 of the 52 significand bits. The value then lies in the range * [1.0, 2.0), from which we simply subtract 1.0. */ @@ -74,13 +74,13 @@ pub fn x_to_float64(x: u64) -> c_double { /// Get the high 31 bits of a 48-bit integer (for `lrand48()` and /// `nrand48()`). -pub fn x_to_uint31(x: u64) -> c_long { +pub fn uint31_from_x(x: u64) -> c_long { (x >> 17) as c_long } /// Get the high 32 bits, signed, of a 48-bit integer (for `mrand48()` /// and `jrand48()`). -pub fn x_to_int32(x: u64) -> c_long { +pub fn int32_from_x(x: u64) -> c_long { // Cast via i32 to ensure we get the sign correct c_long::from((x >> 16) as i32) } diff --git a/src/header/stdlib/mod.rs b/src/header/stdlib/mod.rs index 995ce5b2a8..4ee293fa20 100644 --- a/src/header/stdlib/mod.rs +++ b/src/header/stdlib/mod.rs @@ -233,7 +233,7 @@ pub extern "C" fn div(numer: c_int, denom: c_int) -> div_t { #[no_mangle] pub unsafe extern "C" fn drand48() -> c_double { let new_xi = lcg48::generator_step(lcg48::DEFAULT_XI.as_mut_ptr()); - lcg48::x_to_float64(new_xi) + lcg48::float64_from_x(new_xi) } // #[no_mangle] @@ -249,7 +249,7 @@ pub extern "C" fn ecvt( #[no_mangle] pub unsafe extern "C" fn erand48(xsubi: *mut c_ushort) -> c_double { let new_xi = lcg48::generator_step(xsubi); - lcg48::x_to_float64(new_xi) + lcg48::float64_from_x(new_xi) } #[no_mangle] @@ -365,7 +365,7 @@ pub extern "C" fn initstate(seec: c_uint, state: *mut c_char, size: size_t) -> * #[no_mangle] pub unsafe extern "C" fn jrand48(xsubi: *mut c_ushort) -> c_long { let new_xi = lcg48::generator_step(xsubi); - lcg48::x_to_int32(new_xi) + lcg48::int32_from_x(new_xi) } // #[no_mangle] @@ -384,9 +384,9 @@ pub unsafe extern "C" fn lcong48(param: *mut c_ushort) { /* Go through this ptr -> u64 -> ptr conversion to ensure we only * get the lower 16 bits of each element. */ - let new_xi = lcg48::ushort_arr3_to_uint48(param.offset(0)); + let new_xi = lcg48::uint48_from_ushort_arr3(param.offset(0)); lcg48::set_ushort_arr3_from_uint48(lcg48::DEFAULT_XI.as_mut_ptr(), new_xi); - lcg48::A = lcg48::ushort_arr3_to_uint48(param.offset(3)); + lcg48::A = lcg48::uint48_from_ushort_arr3(param.offset(3)); lcg48::C = *param.offset(6) as u16; // c_ushort may be more than 16 bits } @@ -426,7 +426,7 @@ pub extern "C" fn lldiv(numer: c_longlong, denom: c_longlong) -> lldiv_t { #[no_mangle] pub unsafe extern "C" fn lrand48() -> c_long { let new_xi = lcg48::generator_step(lcg48::DEFAULT_XI.as_mut_ptr()); - lcg48::x_to_uint31(new_xi) + lcg48::uint31_from_x(new_xi) } #[no_mangle] @@ -583,13 +583,13 @@ pub extern "C" fn mkstemps(name: *mut c_char, suffix_len: c_int) -> c_int { #[no_mangle] pub unsafe extern "C" fn mrand48() -> c_long { let new_xi = lcg48::generator_step(lcg48::DEFAULT_XI.as_mut_ptr()); - lcg48::x_to_int32(new_xi) + lcg48::int32_from_x(new_xi) } #[no_mangle] pub unsafe extern "C" fn nrand48(xsubi: *mut c_ushort) -> c_long { let new_xi = lcg48::generator_step(xsubi); - lcg48::x_to_uint31(new_xi) + lcg48::uint31_from_x(new_xi) } // #[no_mangle] @@ -710,7 +710,7 @@ pub unsafe extern "C" fn seed48(seed16v: *mut c_ushort) -> *mut c_ushort { lcg48::STASHED_XI = lcg48::DEFAULT_XI; - let new_xi = lcg48::ushort_arr3_to_uint48(seed16v); + let new_xi = lcg48::uint48_from_ushort_arr3(seed16v); lcg48::set_ushort_arr3_from_uint48(lcg48::DEFAULT_XI.as_mut_ptr(), new_xi); lcg48::STASHED_XI.as_mut_ptr() From 7a48107080ef9526419bd48c809658651d80e3b3 Mon Sep 17 00:00:00 2001 From: Peter Limkilde Svendsen Date: Thu, 23 May 2019 21:46:11 +0200 Subject: [PATCH 6/6] Run fmt --- src/header/stdlib/lcg48.rs | 10 +++++----- src/header/stdlib/mod.rs | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/header/stdlib/lcg48.rs b/src/header/stdlib/lcg48.rs index 84bfd45c01..a425110b04 100644 --- a/src/header/stdlib/lcg48.rs +++ b/src/header/stdlib/lcg48.rs @@ -26,13 +26,13 @@ pub unsafe fn reset_a_and_c() { } /// Build a 48-bit integer from a size-3 array of unsigned short. -/// +/// /// Takes a pointer argument due to the inappropriate C function /// signatures generated from Rust's sized arrays, see /// https://github.com/eqrion/cbindgen/issues/171 pub unsafe fn uint48_from_ushort_arr3(arr_ptr: *const c_ushort) -> u64 { let arr = [*arr_ptr.offset(0), *arr_ptr.offset(1), *arr_ptr.offset(2)]; - + /* Cast via u16 to ensure we get only the lower 16 bits of each * element, as specified by POSIX. */ u64::from(arr[0] as u16) | (u64::from(arr[1] as u16) << 16) | (u64::from(arr[2] as u16) << 32) @@ -47,18 +47,18 @@ pub unsafe fn set_ushort_arr3_from_uint48(arr_ptr: *mut c_ushort, value: u64) { /// Advances the buffer from the input argument to the next element in /// the linear congruential generator's sequence. -/// +/// /// Modifies the passed argument in-place and returns the new value as a /// u64. The input argument must be a size-3 array. pub unsafe fn generator_step(xi_arr_ptr: *mut c_ushort) -> u64 { let old_xi: u64 = uint48_from_ushort_arr3(xi_arr_ptr); - + /* The recurrence relation of the linear congruential generator, * X_(n+1) = (a * X_n + c) % m, * with m = 2**48. The multiplication and addition can overflow a * u64, but we just let it wrap since we take mod 2**48 anyway. */ let new_xi: u64 = A.wrapping_mul(old_xi).wrapping_add(u64::from(C)) & 0xffff_ffff_ffff; - + set_ushort_arr3_from_uint48(xi_arr_ptr, new_xi); new_xi } diff --git a/src/header/stdlib/mod.rs b/src/header/stdlib/mod.rs index 4ee293fa20..172772da1a 100644 --- a/src/header/stdlib/mod.rs +++ b/src/header/stdlib/mod.rs @@ -1,7 +1,7 @@ //! stdlib implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/stdlib.h.html -use core::{intrinsics, iter, mem, ptr, slice}; use core::convert::TryFrom; +use core::{intrinsics, iter, mem, ptr, slice}; use rand::distributions::{Alphanumeric, Distribution, Uniform}; use rand::prng::XorShiftRng; use rand::rngs::JitterRng; @@ -381,7 +381,7 @@ pub extern "C" fn labs(i: c_long) -> c_long { #[no_mangle] pub unsafe extern "C" fn lcong48(param: *mut c_ushort) { // Input should be a size-7 array. - + /* Go through this ptr -> u64 -> ptr conversion to ensure we only * get the lower 16 bits of each element. */ let new_xi = lcg48::uint48_from_ushort_arr3(param.offset(0)); @@ -707,12 +707,12 @@ pub unsafe extern "C" fn realpath(pathname: *const c_char, resolved: *mut c_char #[no_mangle] pub unsafe extern "C" fn seed48(seed16v: *mut c_ushort) -> *mut c_ushort { lcg48::reset_a_and_c(); - + lcg48::STASHED_XI = lcg48::DEFAULT_XI; - + let new_xi = lcg48::uint48_from_ushort_arr3(seed16v); lcg48::set_ushort_arr3_from_uint48(lcg48::DEFAULT_XI.as_mut_ptr(), new_xi); - + lcg48::STASHED_XI.as_mut_ptr() } @@ -801,7 +801,7 @@ pub unsafe extern "C" fn srand(seed: c_uint) { #[no_mangle] pub unsafe extern "C" fn srand48(seedval: c_long) { lcg48::reset_a_and_c(); - + /* Set the high 32 bits of the 48-bit X_i value to the lower 32 bits * of the input argument, and the lower 16 bits to 0x330e, as * specified in POSIX. */