Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
R
relibc
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Container Registry
Model registry
Operate
Environments
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
redox-os
relibc
Commits
fe4a3ae2
Commit
fe4a3ae2
authored
5 years ago
by
Peter Limkilde Svendsen
Browse files
Options
Downloads
Patches
Plain Diff
Refactor for consistency
parent
b2a9cdf9
No related branches found
Branches containing commit
No related tags found
1 merge request
!219
Implement remaining LCG functions
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
src/header/stdlib/lcg48.rs
+53
-42
53 additions, 42 deletions
src/header/stdlib/lcg48.rs
src/header/stdlib/mod.rs
+20
-22
20 additions, 22 deletions
src/header/stdlib/mod.rs
with
73 additions
and
64 deletions
src/header/stdlib/lcg48.rs
+
53
−
42
View file @
fe4a3ae2
...
...
@@ -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
)
}
This diff is collapsed.
Click to expand it.
src/header/stdlib/mod.rs
+
20
−
22
View file @
fe4a3ae2
...
...
@@ -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
{
l
cg48
::
XI
=
lcg48
::
next_x
(
lcg48
::
XI
);
lcg48
::
x_to_float64
(
lcg48
::
XI
)
l
et
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
{
l
cg48
::
XI
=
lcg48
::
next_x
(
lcg48
::
XI
);
lcg48
::
x_to_uint31
(
lcg48
::
XI
)
l
et
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
{
l
cg48
::
XI
=
lcg48
::
next_x
(
lcg48
::
XI
);
lcg48
::
x_to_int32
(
lcg48
::
XI
)
l
et
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]
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment