std: improve rand implementation and API
This commit is contained in:
parent
bc81ddfea6
commit
06c4b35eb1
@ -6,13 +6,11 @@ const os = std.os;
|
|||||||
pub fn main(args: [][]u8) -> %void {
|
pub fn main(args: [][]u8) -> %void {
|
||||||
%%io.stdout.printf("Welcome to the Guess Number Game in Zig.\n");
|
%%io.stdout.printf("Welcome to the Guess Number Game in Zig.\n");
|
||||||
|
|
||||||
var seed : u32 = undefined;
|
var seed: [@sizeof(usize)]u8 = undefined;
|
||||||
const seed_bytes = (&u8)(&seed)[0...4];
|
%%os.get_random_bytes(seed);
|
||||||
%%os.get_random_bytes(seed_bytes);
|
var rand = Rand.init(([]usize)(seed)[0]);
|
||||||
|
|
||||||
var rand = Rand.init(seed);
|
const answer = rand.range_unsigned(u8, 0, 100) + 1;
|
||||||
|
|
||||||
const answer = rand.range_u64(0, 100) + 1;
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
%%io.stdout.printf("\nGuess a number between 1 and 100: ");
|
%%io.stdout.printf("\nGuess a number between 1 and 100: ");
|
||||||
|
@ -387,6 +387,7 @@ enum CastOp {
|
|||||||
CastOpBoolToInt,
|
CastOpBoolToInt,
|
||||||
CastOpResizeSlice,
|
CastOpResizeSlice,
|
||||||
CastOpIntToEnum,
|
CastOpIntToEnum,
|
||||||
|
CastOpBytesToSlice,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AstNodeFnCallExpr {
|
struct AstNodeFnCallExpr {
|
||||||
@ -1311,6 +1312,7 @@ struct VariableTableEntry {
|
|||||||
int gen_arg_index;
|
int gen_arg_index;
|
||||||
BlockContext *block_context;
|
BlockContext *block_context;
|
||||||
LLVMValueRef param_value_ref;
|
LLVMValueRef param_value_ref;
|
||||||
|
bool force_depends_on_compile_var;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ErrorTableEntry {
|
struct ErrorTableEntry {
|
||||||
|
@ -3038,7 +3038,7 @@ static TypeTableEntry *analyze_var_ref(CodeGen *g, AstNode *source_node, Variabl
|
|||||||
ConstExprValue *other_const_val = &get_resolved_expr(var->val_node)->const_val;
|
ConstExprValue *other_const_val = &get_resolved_expr(var->val_node)->const_val;
|
||||||
if (other_const_val->ok) {
|
if (other_const_val->ok) {
|
||||||
return resolve_expr_const_val_as_other_expr(g, source_node, var->val_node,
|
return resolve_expr_const_val_as_other_expr(g, source_node, var->val_node,
|
||||||
depends_on_compile_var);
|
depends_on_compile_var || var->force_depends_on_compile_var);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return var->type;
|
return var->type;
|
||||||
@ -3959,12 +3959,12 @@ static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import,
|
|||||||
{
|
{
|
||||||
assert(node->type == NodeTypeWhileExpr);
|
assert(node->type == NodeTypeWhileExpr);
|
||||||
|
|
||||||
AstNode *condition_node = node->data.while_expr.condition;
|
AstNode **condition_node = &node->data.while_expr.condition;
|
||||||
AstNode *while_body_node = node->data.while_expr.body;
|
AstNode *while_body_node = node->data.while_expr.body;
|
||||||
AstNode **continue_expr_node = &node->data.while_expr.continue_expr;
|
AstNode **continue_expr_node = &node->data.while_expr.continue_expr;
|
||||||
|
|
||||||
TypeTableEntry *condition_type = analyze_expression(g, import, context,
|
TypeTableEntry *condition_type = analyze_expression(g, import, context,
|
||||||
g->builtin_types.entry_bool, condition_node);
|
g->builtin_types.entry_bool, *condition_node);
|
||||||
|
|
||||||
if (*continue_expr_node) {
|
if (*continue_expr_node) {
|
||||||
analyze_expression(g, import, context, g->builtin_types.entry_void, *continue_expr_node);
|
analyze_expression(g, import, context, g->builtin_types.entry_void, *continue_expr_node);
|
||||||
@ -3983,7 +3983,7 @@ static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import,
|
|||||||
} else {
|
} else {
|
||||||
// if the condition is a simple constant expression and there are no break statements
|
// if the condition is a simple constant expression and there are no break statements
|
||||||
// then the return type is unreachable
|
// then the return type is unreachable
|
||||||
ConstExprValue *const_val = &get_resolved_expr(condition_node)->const_val;
|
ConstExprValue *const_val = &get_resolved_expr(*condition_node)->const_val;
|
||||||
if (const_val->ok) {
|
if (const_val->ok) {
|
||||||
if (const_val->data.x_bool) {
|
if (const_val->data.x_bool) {
|
||||||
node->data.while_expr.condition_always_true = true;
|
node->data.while_expr.condition_always_true = true;
|
||||||
@ -4392,6 +4392,24 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B
|
|||||||
return resolve_cast(g, context, node, expr_node, wanted_type, CastOpResizeSlice, true);
|
return resolve_cast(g, context, node, expr_node, wanted_type, CastOpResizeSlice, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// explicit cast from [N]u8 to []T
|
||||||
|
if (is_slice(wanted_type) &&
|
||||||
|
actual_type->id == TypeTableEntryIdArray &&
|
||||||
|
is_u8(actual_type->data.array.child_type))
|
||||||
|
{
|
||||||
|
mark_impure_fn(context);
|
||||||
|
uint64_t child_type_size = type_size(g,
|
||||||
|
wanted_type->data.structure.fields[0].type_entry->data.pointer.child_type);
|
||||||
|
if (actual_type->data.array.len % child_type_size == 0) {
|
||||||
|
return resolve_cast(g, context, node, expr_node, wanted_type, CastOpBytesToSlice, true);
|
||||||
|
} else {
|
||||||
|
add_node_error(g, node,
|
||||||
|
buf_sprintf("unable to convert %s to %s: size mismatch",
|
||||||
|
buf_ptr(&actual_type->name), buf_ptr(&wanted_type->name)));
|
||||||
|
return g->builtin_types.entry_invalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// explicit cast from pointer to another pointer
|
// explicit cast from pointer to another pointer
|
||||||
if ((actual_type->id == TypeTableEntryIdPointer || actual_type->id == TypeTableEntryIdFn) &&
|
if ((actual_type->id == TypeTableEntryIdPointer || actual_type->id == TypeTableEntryIdFn) &&
|
||||||
(wanted_type->id == TypeTableEntryIdPointer || wanted_type->id == TypeTableEntryIdFn))
|
(wanted_type->id == TypeTableEntryIdPointer || wanted_type->id == TypeTableEntryIdFn))
|
||||||
@ -5062,8 +5080,10 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
|
|||||||
return g->builtin_types.entry_invalid;
|
return g->builtin_types.entry_invalid;
|
||||||
} else {
|
} else {
|
||||||
uint64_t size_in_bytes = type_size(g, type_entry);
|
uint64_t size_in_bytes = type_size(g, type_entry);
|
||||||
|
bool depends_on_compile_var = (type_entry == g->builtin_types.entry_usize ||
|
||||||
|
type_entry == g->builtin_types.entry_isize);
|
||||||
return resolve_expr_const_val_as_unsigned_num_lit(g, node, expected_type,
|
return resolve_expr_const_val_as_unsigned_num_lit(g, node, expected_type,
|
||||||
size_in_bytes, false);
|
size_in_bytes, depends_on_compile_var);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case BuiltinFnIdAlignof:
|
case BuiltinFnIdAlignof:
|
||||||
@ -5461,8 +5481,11 @@ static TypeTableEntry *analyze_fn_call_with_inline_args(CodeGen *g, ImportTableE
|
|||||||
|
|
||||||
ConstExprValue *const_val = &get_resolved_expr(*param_node)->const_val;
|
ConstExprValue *const_val = &get_resolved_expr(*param_node)->const_val;
|
||||||
if (const_val->ok) {
|
if (const_val->ok) {
|
||||||
add_local_var(g, generic_param_decl_node, decl_node->owner, child_context,
|
VariableTableEntry *var = add_local_var(g, generic_param_decl_node, decl_node->owner, child_context,
|
||||||
&generic_param_decl_node->data.param_decl.name, param_type, true, *param_node);
|
&generic_param_decl_node->data.param_decl.name, param_type, true, *param_node);
|
||||||
|
// This generic function instance could be called with anything, so when this variable is read it
|
||||||
|
// needs to know that it depends on compile time variable data.
|
||||||
|
var->force_depends_on_compile_var = true;
|
||||||
} else {
|
} else {
|
||||||
add_node_error(g, *param_node,
|
add_node_error(g, *param_node,
|
||||||
buf_sprintf("unable to evaluate constant expression for inline parameter"));
|
buf_sprintf("unable to evaluate constant expression for inline parameter"));
|
||||||
@ -5552,8 +5575,9 @@ static TypeTableEntry *analyze_generic_fn_call(CodeGen *g, ImportTableEntry *imp
|
|||||||
|
|
||||||
ConstExprValue *const_val = &get_resolved_expr(*param_node)->const_val;
|
ConstExprValue *const_val = &get_resolved_expr(*param_node)->const_val;
|
||||||
if (const_val->ok) {
|
if (const_val->ok) {
|
||||||
add_local_var(g, generic_param_decl_node, decl_node->owner, child_context,
|
VariableTableEntry *var = add_local_var(g, generic_param_decl_node, decl_node->owner, child_context,
|
||||||
&generic_param_decl_node->data.param_decl.name, param_type, true, *param_node);
|
&generic_param_decl_node->data.param_decl.name, param_type, true, *param_node);
|
||||||
|
var->force_depends_on_compile_var = true;
|
||||||
} else {
|
} else {
|
||||||
add_node_error(g, *param_node, buf_sprintf("unable to evaluate constant expression"));
|
add_node_error(g, *param_node, buf_sprintf("unable to evaluate constant expression"));
|
||||||
|
|
||||||
|
@ -1005,6 +1005,31 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {
|
|||||||
LLVMBuildStore(g->builder, new_len, dest_len_ptr);
|
LLVMBuildStore(g->builder, new_len, dest_len_ptr);
|
||||||
|
|
||||||
|
|
||||||
|
return cast_expr->tmp_ptr;
|
||||||
|
}
|
||||||
|
case CastOpBytesToSlice:
|
||||||
|
{
|
||||||
|
assert(cast_expr->tmp_ptr);
|
||||||
|
assert(wanted_type->id == TypeTableEntryIdStruct);
|
||||||
|
assert(wanted_type->data.structure.is_slice);
|
||||||
|
assert(actual_type->id == TypeTableEntryIdArray);
|
||||||
|
|
||||||
|
TypeTableEntry *wanted_pointer_type = wanted_type->data.structure.fields[0].type_entry;
|
||||||
|
TypeTableEntry *wanted_child_type = wanted_pointer_type->data.pointer.child_type;
|
||||||
|
|
||||||
|
set_debug_source_node(g, node);
|
||||||
|
|
||||||
|
int wanted_ptr_index = wanted_type->data.structure.fields[0].gen_index;
|
||||||
|
LLVMValueRef dest_ptr_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr, wanted_ptr_index, "");
|
||||||
|
LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, expr_val, wanted_pointer_type->type_ref, "");
|
||||||
|
LLVMBuildStore(g->builder, src_ptr_casted, dest_ptr_ptr);
|
||||||
|
|
||||||
|
int wanted_len_index = wanted_type->data.structure.fields[1].gen_index;
|
||||||
|
LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr, wanted_len_index, "");
|
||||||
|
LLVMValueRef len_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref,
|
||||||
|
actual_type->data.array.len / type_size(g, wanted_child_type), false);
|
||||||
|
LLVMBuildStore(g->builder, len_val, len_ptr);
|
||||||
|
|
||||||
return cast_expr->tmp_ptr;
|
return cast_expr->tmp_ptr;
|
||||||
}
|
}
|
||||||
case CastOpIntToFloat:
|
case CastOpIntToFloat:
|
||||||
|
@ -601,6 +601,7 @@ void eval_const_expr_implicit_cast(CastOp cast_op,
|
|||||||
case CastOpPtrToInt:
|
case CastOpPtrToInt:
|
||||||
case CastOpIntToPtr:
|
case CastOpIntToPtr:
|
||||||
case CastOpResizeSlice:
|
case CastOpResizeSlice:
|
||||||
|
case CastOpBytesToSlice:
|
||||||
// can't do it
|
// can't do it
|
||||||
break;
|
break;
|
||||||
case CastOpToUnknownSizeArray:
|
case CastOpToUnknownSizeArray:
|
||||||
|
@ -3301,6 +3301,8 @@ AstNode *ast_clone_subtree_special(AstNode *old_node, uint32_t *next_node_index,
|
|||||||
case NodeTypeWhileExpr:
|
case NodeTypeWhileExpr:
|
||||||
clone_subtree_field(&new_node->data.while_expr.condition, old_node->data.while_expr.condition, next_node_index);
|
clone_subtree_field(&new_node->data.while_expr.condition, old_node->data.while_expr.condition, next_node_index);
|
||||||
clone_subtree_field(&new_node->data.while_expr.body, old_node->data.while_expr.body, next_node_index);
|
clone_subtree_field(&new_node->data.while_expr.body, old_node->data.while_expr.body, next_node_index);
|
||||||
|
clone_subtree_field(&new_node->data.while_expr.continue_expr,
|
||||||
|
old_node->data.while_expr.continue_expr, next_node_index);
|
||||||
break;
|
break;
|
||||||
case NodeTypeForExpr:
|
case NodeTypeForExpr:
|
||||||
clone_subtree_field(&new_node->data.for_expr.elem_node, old_node->data.for_expr.elem_node, next_node_index);
|
clone_subtree_field(&new_node->data.for_expr.elem_node, old_node->data.for_expr.elem_node, next_node_index);
|
||||||
|
@ -145,7 +145,6 @@ LLVMZigDISubprogram *LLVMZigCreateFunction(LLVMZigDIBuilder *dibuilder, LLVMZigD
|
|||||||
LLVMZigDIType *fn_di_type, bool is_local_to_unit, bool is_definition, unsigned scope_line,
|
LLVMZigDIType *fn_di_type, bool is_local_to_unit, bool is_definition, unsigned scope_line,
|
||||||
unsigned flags, bool is_optimized, LLVMZigDISubprogram *decl_subprogram);
|
unsigned flags, bool is_optimized, LLVMZigDISubprogram *decl_subprogram);
|
||||||
|
|
||||||
|
|
||||||
void ZigLLVMFnSetSubprogram(LLVMValueRef fn, LLVMZigDISubprogram *subprogram);
|
void ZigLLVMFnSetSubprogram(LLVMValueRef fn, LLVMZigDISubprogram *subprogram);
|
||||||
|
|
||||||
void LLVMZigDIBuilderFinalize(LLVMZigDIBuilder *dibuilder);
|
void LLVMZigDIBuilderFinalize(LLVMZigDIBuilder *dibuilder);
|
||||||
|
196
std/rand.zig
196
std/rand.zig
@ -1,51 +1,57 @@
|
|||||||
// Mersenne Twister
|
const assert = @import("debug.zig").assert;
|
||||||
const ARRAY_SIZE = 624;
|
|
||||||
|
pub const MT19937_32 = MersenneTwister(
|
||||||
|
u32, 624, 397, 31,
|
||||||
|
0x9908B0DF,
|
||||||
|
11, 0xFFFFFFFF,
|
||||||
|
7, 0x9D2C5680,
|
||||||
|
15, 0xEFC60000,
|
||||||
|
18, 1812433253);
|
||||||
|
|
||||||
|
pub const MT19937_64 = MersenneTwister(
|
||||||
|
u64, 312, 156, 31,
|
||||||
|
0xB5026F5AA96619E9,
|
||||||
|
29, 0x5555555555555555,
|
||||||
|
17, 0x71D67FFFEDA60000,
|
||||||
|
37, 0xFFF7EEE000000000,
|
||||||
|
43, 6364136223846793005);
|
||||||
|
|
||||||
/// Use `init` to initialize this state.
|
/// Use `init` to initialize this state.
|
||||||
pub struct Rand {
|
pub struct Rand {
|
||||||
array: [ARRAY_SIZE]u32,
|
const Rng = if (@sizeof(usize) >= 8) MT19937_64 else MT19937_32;
|
||||||
index: usize,
|
|
||||||
|
rng: Rng,
|
||||||
|
|
||||||
/// Initialize random state with the given seed.
|
/// Initialize random state with the given seed.
|
||||||
#static_eval_enable(false)
|
pub fn init(seed: usize) -> Rand {
|
||||||
pub fn init(seed: u32) -> Rand {
|
|
||||||
var r: Rand = undefined;
|
var r: Rand = undefined;
|
||||||
r.index = 0;
|
r.rng = Rng.init(seed);
|
||||||
r.array[0] = seed;
|
|
||||||
var i : usize = 1;
|
|
||||||
var prev_value: u64w = seed;
|
|
||||||
while (i < ARRAY_SIZE; i += 1) {
|
|
||||||
r.array[i] = @truncate(u32, (prev_value ^ (prev_value << 30)) * 0x6c078965 + u64w(i));
|
|
||||||
prev_value = r.array[i];
|
|
||||||
}
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get 32 bits of randomness.
|
/// Get an integer with random bits.
|
||||||
pub fn get_u32(r: &Rand) -> u32 {
|
pub fn scalar(r: &Rand, inline T: type) -> T {
|
||||||
if (r.index == 0) {
|
if (T == usize) {
|
||||||
r.generate_numbers();
|
return r.rng.get();
|
||||||
|
} else {
|
||||||
|
var result: T = undefined;
|
||||||
|
r.fill_bytes(([]u8)((&result)[0...@sizeof(T)]));
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// temper the number
|
|
||||||
var y : u32 = r.array[r.index];
|
|
||||||
y ^= y >> 11;
|
|
||||||
y ^= (y >> 7) & 0x9d2c5680;
|
|
||||||
y ^= (y >> 15) & 0xefc60000;
|
|
||||||
y ^= y >> 18;
|
|
||||||
|
|
||||||
r.index = (r.index + 1) % ARRAY_SIZE;
|
|
||||||
return y;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fill `buf` with randomness.
|
/// Fill `buf` with randomness.
|
||||||
pub fn get_bytes(r: &Rand, buf: []u8) {
|
pub fn fill_bytes(r: &Rand, buf: []u8) {
|
||||||
var bytes_left = r.get_bytes_aligned(buf);
|
var bytes_left = buf.len;
|
||||||
|
while (bytes_left >= @sizeof(usize)) {
|
||||||
|
*((&usize)(&buf[buf.len - bytes_left])) = r.scalar(usize);
|
||||||
|
bytes_left -= @sizeof(usize);
|
||||||
|
}
|
||||||
if (bytes_left > 0) {
|
if (bytes_left > 0) {
|
||||||
var rand_val_array : [@sizeof(u32)]u8 = undefined;
|
var rand_val_array : [@sizeof(usize)]u8 = undefined;
|
||||||
*((&u32)(&rand_val_array[0])) = r.get_u32();
|
([]usize)(rand_val_array)[0] = r.scalar(usize);
|
||||||
while (bytes_left > 0) {
|
while (bytes_left > 0) {
|
||||||
buf[buf.len - bytes_left] = rand_val_array[@sizeof(u32) - bytes_left];
|
buf[buf.len - bytes_left] = rand_val_array[@sizeof(usize) - bytes_left];
|
||||||
bytes_left -= 1;
|
bytes_left -= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -53,61 +59,119 @@ pub struct Rand {
|
|||||||
|
|
||||||
/// Get a random unsigned integer with even distribution between `start`
|
/// Get a random unsigned integer with even distribution between `start`
|
||||||
/// inclusive and `end` exclusive.
|
/// inclusive and `end` exclusive.
|
||||||
pub fn range_u64(r: &Rand, start: u64, end: u64) -> u64 {
|
// TODO support signed integers and then rename to "range"
|
||||||
|
pub fn range_unsigned(r: &Rand, inline T: type, start: T, end: T) -> T {
|
||||||
const range = end - start;
|
const range = end - start;
|
||||||
const leftover = @max_value(u64) % range;
|
const leftover = @max_value(T) % range;
|
||||||
const upper_bound = @max_value(u64) - leftover;
|
const upper_bound = @max_value(T) - leftover;
|
||||||
var rand_val_array : [@sizeof(u64)]u8 = undefined;
|
var rand_val_array : [@sizeof(T)]u8 = undefined;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
r.get_bytes_aligned(rand_val_array);
|
r.fill_bytes(rand_val_array);
|
||||||
const rand_val = *(&u64)(&rand_val_array[0]);
|
const rand_val = ([]T)(rand_val_array)[0];
|
||||||
if (rand_val < upper_bound) {
|
if (rand_val < upper_bound) {
|
||||||
return start + (rand_val % range);
|
return start + (rand_val % range);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn float32(r: &Rand) -> f32 {
|
/// Get a floating point value in the range 0.0..1.0.
|
||||||
const precision = 16777216;
|
pub fn float(r: &Rand, inline T: type) -> T {
|
||||||
return f32(r.range_u64(0, precision)) / precision;
|
const int_type = @int_type(false, @sizeof(T) * 8, false);
|
||||||
|
// TODO switch statement for constant values
|
||||||
|
const precision = if (T == f32) {
|
||||||
|
16777216
|
||||||
|
} else if (T == f64) {
|
||||||
|
9007199254740992
|
||||||
|
} else {
|
||||||
|
@compile_err("unknown floating point type" ++ @type_name(T))
|
||||||
|
};
|
||||||
|
return T(r.range_unsigned(int_type, 0, precision)) / T(precision);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MersenneTwister(
|
||||||
|
int: type, n: usize, m: usize, r: int,
|
||||||
|
a: int,
|
||||||
|
u: int, d: int,
|
||||||
|
s: int, b: int,
|
||||||
|
t: int, c: int,
|
||||||
|
l: int, f: int)
|
||||||
|
{
|
||||||
|
const Self = MersenneTwister(int, n, m, r, a, u, d, s, b, t, c, l, f);
|
||||||
|
const intw = @int_type(int.is_signed, int.bit_count, true);
|
||||||
|
|
||||||
|
array: [n]int,
|
||||||
|
index: usize,
|
||||||
|
|
||||||
|
// TODO improve compile time eval code and then allow this function to be executed at compile time.
|
||||||
|
#static_eval_enable(false)
|
||||||
|
pub fn init(seed: int) -> Self {
|
||||||
|
var mt = Self {
|
||||||
|
.index = n,
|
||||||
|
.array = undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
var prev_value = seed;
|
||||||
|
mt.array[0] = prev_value;
|
||||||
|
{var i: usize = 1; while (i < n; i += 1) {
|
||||||
|
prev_value = intw(i) + intw(f) * intw(prev_value ^ (prev_value >> (int.bit_count - 2)));
|
||||||
|
mt.array[i] = prev_value;
|
||||||
|
}};
|
||||||
|
|
||||||
|
return mt;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn boolean(r: &Rand) -> bool {
|
pub fn get(mt: &Self) -> int {
|
||||||
return (r.get_u32() & 0x1) == 1;
|
const mag01 = []int{0, a};
|
||||||
}
|
const LM: int = (1 << r) - 1;
|
||||||
|
const UM = ~LM;
|
||||||
|
|
||||||
fn generate_numbers(r: &Rand) {
|
if (int.bit_count == 64) {
|
||||||
for (r.array) |item, i| {
|
assert(LM == 0x7fffffff);
|
||||||
const y : u32 = (item & 0x80000000) + (r.array[(i + 1) % ARRAY_SIZE] & 0x7fffffff);
|
assert(UM == 0xffffffff80000000);
|
||||||
const untempered : u32 = r.array[(i + 397) % ARRAY_SIZE] ^ (y >> 1);
|
} else if (int.bit_count == 32) {
|
||||||
r.array[i] = if ((y % 2) == 0) {
|
assert(LM == 0x7fffffff);
|
||||||
untempered
|
assert(UM == 0x80000000);
|
||||||
} else {
|
|
||||||
// y is odd
|
|
||||||
untempered ^ 0x9908b0df
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// does not populate the remaining (buf.len % 4) bytes
|
if (mt.index >= n) {
|
||||||
fn get_bytes_aligned(r: &Rand, buf: []u8) -> usize {
|
var i: usize = 0;
|
||||||
var bytes_left = buf.len;
|
|
||||||
while (bytes_left >= 4) {
|
while (i < n - m; i += 1) {
|
||||||
*((&u32)(&buf[buf.len - bytes_left])) = r.get_u32();
|
const x = (mt.array[i] & UM) | (mt.array[i + 1] & LM);
|
||||||
bytes_left -= @sizeof(u32);
|
mt.array[i] = mt.array[i + m] ^ (x >> 1) ^ mag01[x & 0x1];
|
||||||
|
}
|
||||||
|
|
||||||
|
while (i < n - 1; i += 1) {
|
||||||
|
const x = (mt.array[i] & UM) | (mt.array[i + 1] & LM);
|
||||||
|
mt.array[i] = mt.array[i + m - n] ^ (x >> 1) ^ mag01[x & 0x1];
|
||||||
|
|
||||||
|
}
|
||||||
|
const x = (mt.array[i] & UM) | (mt.array[0] & LM);
|
||||||
|
mt.array[i] = mt.array[m - 1] ^ (x >> 1) ^ mag01[x & 0x1];
|
||||||
|
|
||||||
|
mt.index = 0;
|
||||||
}
|
}
|
||||||
return bytes_left;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
var x: intw = mt.array[mt.index];
|
||||||
|
mt.index += 1;
|
||||||
|
|
||||||
|
x ^= ((x >> u) & d);
|
||||||
|
x ^= ((x << s) & b);
|
||||||
|
x ^= ((x << t) & c);
|
||||||
|
x ^= (x >> l);
|
||||||
|
|
||||||
|
return x;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#attribute("test")
|
#attribute("test")
|
||||||
fn test_float32() {
|
fn test_float32() {
|
||||||
var r = Rand.init(42);
|
var r = Rand.init(42);
|
||||||
|
|
||||||
{var i: i32 = 0; while (i < 1000; i += 1) {
|
{var i: usize = 0; while (i < 1000; i += 1) {
|
||||||
const val = r.float32();
|
const val = r.float(f32);
|
||||||
if (!(val >= 0.0)) unreachable{};
|
if (!(val >= 0.0)) unreachable{};
|
||||||
if (!(val < 1.0)) unreachable{};
|
if (!(val < 1.0)) unreachable{};
|
||||||
}}
|
}}
|
||||||
|
@ -1427,6 +1427,12 @@ export inline fn foo(x: i32, y: i32) -> i32{
|
|||||||
)SOURCE", 1, ".tmp_source.zig:2:1: error: extern functions cannot be inline");
|
)SOURCE", 1, ".tmp_source.zig:2:1: error: extern functions cannot be inline");
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
add_compile_fail_case("convert fixed size array to slice with invalid size", R"SOURCE(
|
||||||
|
fn f() {
|
||||||
|
var array: [5]u8 = undefined;
|
||||||
|
var foo = ([]u32)(array)[0];
|
||||||
|
}
|
||||||
|
)SOURCE", 1, ".tmp_source.zig:4:22: error: unable to convert [5]u8 to []u32: size mismatch");
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
Loading…
x
Reference in New Issue
Block a user