Skip to content
Snippets Groups Projects
Commit fe4a3ae2 authored by Peter Limkilde Svendsen's avatar Peter Limkilde Svendsen
Browse files

Refactor for consistency

parent b2a9cdf9
No related branches found
No related tags found
1 merge request!219Implement remaining LCG functions
......@@ -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)
}
......@@ -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]
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment