2
0

lcg48.rs 3.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. //! Helper functions for pseudorandom number generation using LCG, see https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/functions/drand48.html
  2. use platform::types::*;
  3. /* The default element buffer for the linear congruential generator's
  4. * sequence. Implemented using a c_ushort array for consistency between
  5. * the drand48()/lrand48()/mrand48() and erand48()/nrand48()/jrand48()
  6. * functions, and with STASHED_XI (see below). */
  7. pub static mut DEFAULT_XI: [c_ushort; 3] = [0; 3];
  8. // Used by seed48() (returns a pointer to this array).
  9. pub static mut STASHED_XI: [c_ushort; 3] = [0; 3];
  10. /* Multiplier and addend, which may be set through lcong48(). Default
  11. * values as specified in POSIX. */
  12. const A_DEFAULT_VALUE: u64 = 0x5deece66d;
  13. const C_DEFAULT_VALUE: u16 = 0xb;
  14. pub static mut A: u64 = A_DEFAULT_VALUE;
  15. pub static mut C: u16 = C_DEFAULT_VALUE;
  16. /// Used by `srand48()` and `seed48()`.
  17. pub unsafe fn reset_a_and_c() {
  18. A = A_DEFAULT_VALUE;
  19. C = C_DEFAULT_VALUE;
  20. }
  21. /// Build a 48-bit integer from a size-3 array of unsigned short.
  22. ///
  23. /// Takes a pointer argument due to the inappropriate C function
  24. /// signatures generated from Rust's sized arrays, see
  25. /// https://github.com/eqrion/cbindgen/issues/171
  26. pub unsafe fn ushort_arr3_to_uint48(arr_ptr: *const c_ushort) -> u64 {
  27. let arr = [*arr_ptr.offset(0), *arr_ptr.offset(1), *arr_ptr.offset(2)];
  28. /* Cast via u16 to ensure we get only the lower 16 bits of each
  29. * element, as specified by POSIX. */
  30. u64::from(arr[0] as u16) | (u64::from(arr[1] as u16) << 16) | (u64::from(arr[2] as u16) << 32)
  31. }
  32. /// Set a size-3 array of unsigned short from a 48-bit integer.
  33. pub unsafe fn set_ushort_arr3_from_uint48(arr_ptr: *mut c_ushort, value: u64) {
  34. *arr_ptr.offset(0) = c_ushort::from(value as u16);
  35. *arr_ptr.offset(1) = c_ushort::from((value >> 16) as u16);
  36. *arr_ptr.offset(2) = c_ushort::from((value >> 32) as u16);
  37. }
  38. /// Advances the buffer from the input argument to the next element in
  39. /// the linear congruential generator's sequence.
  40. ///
  41. /// Modifies the passed argument in-place and returns the new value as a
  42. /// u64. The input argument must be a size-3 array.
  43. pub unsafe fn generator_step(xi_arr_ptr: *mut c_ushort) -> u64 {
  44. let old_xi: u64 = ushort_arr3_to_uint48(xi_arr_ptr);
  45. /* The recurrence relation of the linear congruential generator,
  46. * X_(n+1) = (a * X_n + c) % m,
  47. * with m = 2**48. The multiplication and addition can overflow a
  48. * u64, but we just let it wrap since we take mod 2**48 anyway. */
  49. let new_xi: u64 = A.wrapping_mul(old_xi).wrapping_add(u64::from(C)) & 0xffff_ffff_ffff;
  50. set_ushort_arr3_from_uint48(xi_arr_ptr, new_xi);
  51. new_xi
  52. }
  53. /// Get a C `double` from a 48-bit integer (for `drand48()` and
  54. /// `erand48()`).
  55. pub fn x_to_float64(x: u64) -> c_double {
  56. /* We set the exponent to 0, and the 48-bit integer is copied into the high
  57. * 48 of the 52 significand bits. The value then lies in the range
  58. * [1.0, 2.0), from which we simply subtract 1.0. */
  59. f64::from_bits(0x3ff0_0000_0000_0000_u64 | (x << 4)) - 1.0f64
  60. }
  61. /// Get the high 31 bits of a 48-bit integer (for `lrand48()` and
  62. /// `nrand48()`).
  63. pub fn x_to_uint31(x: u64) -> c_long {
  64. (x >> 17) as c_long
  65. }
  66. /// Get the high 32 bits, signed, of a 48-bit integer (for `mrand48()`
  67. /// and `jrand48()`).
  68. pub fn x_to_int32(x: u64) -> c_long {
  69. // Cast via i32 to ensure we get the sign correct
  70. c_long::from((x >> 16) as i32)
  71. }