diff --git a/src/header/stdlib/lcg48.rs b/src/header/stdlib/lcg48.rs index 4963d4fddb373f605c73b0c47470ef7d068c088a..a847f742bb049ccfa7d5815261808bc085ceafcb 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 8189dcf4beb07c17218a9f280468208fe93db71d..cb64ae223ddb6ffb60c41bf321529f71f8d96e91 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 40d35e82f48a990e49324fbc071bca11bd52a7aa..fa871030baa911d47a02c434e66f92db34c033f6 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 1d87589e4aabeb40836d63246cddfb11b289c00e..a1685f27fd207ec9f19615bd89fbb95bdfa85bc2 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"); }