Refactor for consistency
This commit is contained in:
+53
-42
@@ -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)
|
||||
}
|
||||
|
||||
+20
-22
@@ -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]
|
||||
|
||||
Reference in New Issue
Block a user