authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-07-26 23:51:58-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-07-26 23:51:58-07:00
log06c4b35eb12a54a4e260a80ed8ed21eb5bfae09a
tree33d8366daa35741ce302df23e2be1e217aa20187
parentbc81ddfea67db0b3756027e98cc00bb8fa903a20

std: improve rand implementation and API


9 files changed, 200 insertions(+), 79 deletions(-)

example/guess_number/main.zig+4-6
...@@ -6,13 +6,11 @@ const os = std.os;...@@ -6,13 +6,11 @@ const os = std.os;
6pub fn main(args: [][]u8) -> %void {6pub fn main(args: [][]u8) -> %void {
7 %%io.stdout.printf("Welcome to the Guess Number Game in Zig.\n");7 %%io.stdout.printf("Welcome to the Guess Number Game in Zig.\n");
88
9 var seed : u32 = undefined;9 var seed: [@sizeof(usize)]u8 = undefined;
10 const seed_bytes = (&u8)(&seed)[0...4];10 %%os.get_random_bytes(seed);
11 %%os.get_random_bytes(seed_bytes);11 var rand = Rand.init(([]usize)(seed)[0]);
1212
13 var rand = Rand.init(seed);13 const answer = rand.range_unsigned(u8, 0, 100) + 1;
14
15 const answer = rand.range_u64(0, 100) + 1;
1614
17 while (true) {15 while (true) {
18 %%io.stdout.printf("\nGuess a number between 1 and 100: ");16 %%io.stdout.printf("\nGuess a number between 1 and 100: ");
src/all_types.hpp+2
...@@ -387,6 +387,7 @@ enum CastOp {...@@ -387,6 +387,7 @@ enum CastOp {
387 CastOpBoolToInt,387 CastOpBoolToInt,
388 CastOpResizeSlice,388 CastOpResizeSlice,
389 CastOpIntToEnum,389 CastOpIntToEnum,
390 CastOpBytesToSlice,
390};391};
391392
392struct AstNodeFnCallExpr {393struct AstNodeFnCallExpr {
...@@ -1311,6 +1312,7 @@ struct VariableTableEntry {...@@ -1311,6 +1312,7 @@ struct VariableTableEntry {
1311 int gen_arg_index;1312 int gen_arg_index;
1312 BlockContext *block_context;1313 BlockContext *block_context;
1313 LLVMValueRef param_value_ref;1314 LLVMValueRef param_value_ref;
1315 bool force_depends_on_compile_var;
1314};1316};
13151317
1316struct ErrorTableEntry {1318struct ErrorTableEntry {
src/analyze.cpp+31-7
...@@ -3038,7 +3038,7 @@ static TypeTableEntry *analyze_var_ref(CodeGen *g, AstNode *source_node, Variabl...@@ -3038,7 +3038,7 @@ static TypeTableEntry *analyze_var_ref(CodeGen *g, AstNode *source_node, Variabl
3038 ConstExprValue *other_const_val = &get_resolved_expr(var->val_node)->const_val;3038 ConstExprValue *other_const_val = &get_resolved_expr(var->val_node)->const_val;
3039 if (other_const_val->ok) {3039 if (other_const_val->ok) {
3040 return resolve_expr_const_val_as_other_expr(g, source_node, var->val_node,3040 return resolve_expr_const_val_as_other_expr(g, source_node, var->val_node,
3041 depends_on_compile_var);3041 depends_on_compile_var || var->force_depends_on_compile_var);
3042 }3042 }
3043 }3043 }
3044 return var->type;3044 return var->type;
...@@ -3959,12 +3959,12 @@ static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import,...@@ -3959,12 +3959,12 @@ static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import,
3959{3959{
3960 assert(node->type == NodeTypeWhileExpr);3960 assert(node->type == NodeTypeWhileExpr);
39613961
3962 AstNode *condition_node = node->data.while_expr.condition;3962 AstNode **condition_node = &node->data.while_expr.condition;
3963 AstNode *while_body_node = node->data.while_expr.body;3963 AstNode *while_body_node = node->data.while_expr.body;
3964 AstNode **continue_expr_node = &node->data.while_expr.continue_expr;3964 AstNode **continue_expr_node = &node->data.while_expr.continue_expr;
39653965
3966 TypeTableEntry *condition_type = analyze_expression(g, import, context,3966 TypeTableEntry *condition_type = analyze_expression(g, import, context,
3967 g->builtin_types.entry_bool, condition_node);3967 g->builtin_types.entry_bool, *condition_node);
39683968
3969 if (*continue_expr_node) {3969 if (*continue_expr_node) {
3970 analyze_expression(g, import, context, g->builtin_types.entry_void, *continue_expr_node);3970 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,...@@ -3983,7 +3983,7 @@ static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import,
3983 } else {3983 } else {
3984 // if the condition is a simple constant expression and there are no break statements3984 // if the condition is a simple constant expression and there are no break statements
3985 // then the return type is unreachable3985 // then the return type is unreachable
3986 ConstExprValue *const_val = &get_resolved_expr(condition_node)->const_val;3986 ConstExprValue *const_val = &get_resolved_expr(*condition_node)->const_val;
3987 if (const_val->ok) {3987 if (const_val->ok) {
3988 if (const_val->data.x_bool) {3988 if (const_val->data.x_bool) {
3989 node->data.while_expr.condition_always_true = true;3989 node->data.while_expr.condition_always_true = true;
...@@ -4392,6 +4392,24 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B...@@ -4392,6 +4392,24 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B
4392 return resolve_cast(g, context, node, expr_node, wanted_type, CastOpResizeSlice, true);4392 return resolve_cast(g, context, node, expr_node, wanted_type, CastOpResizeSlice, true);
4393 }4393 }
43944394
4395 // explicit cast from [N]u8 to []T
4396 if (is_slice(wanted_type) &&
4397 actual_type->id == TypeTableEntryIdArray &&
4398 is_u8(actual_type->data.array.child_type))
4399 {
4400 mark_impure_fn(context);
4401 uint64_t child_type_size = type_size(g,
4402 wanted_type->data.structure.fields[0].type_entry->data.pointer.child_type);
4403 if (actual_type->data.array.len % child_type_size == 0) {
4404 return resolve_cast(g, context, node, expr_node, wanted_type, CastOpBytesToSlice, true);
4405 } else {
4406 add_node_error(g, node,
4407 buf_sprintf("unable to convert %s to %s: size mismatch",
4408 buf_ptr(&actual_type->name), buf_ptr(&wanted_type->name)));
4409 return g->builtin_types.entry_invalid;
4410 }
4411 }
4412
4395 // explicit cast from pointer to another pointer4413 // explicit cast from pointer to another pointer
4396 if ((actual_type->id == TypeTableEntryIdPointer || actual_type->id == TypeTableEntryIdFn) &&4414 if ((actual_type->id == TypeTableEntryIdPointer || actual_type->id == TypeTableEntryIdFn) &&
4397 (wanted_type->id == TypeTableEntryIdPointer || wanted_type->id == TypeTableEntryIdFn))4415 (wanted_type->id == TypeTableEntryIdPointer || wanted_type->id == TypeTableEntryIdFn))
...@@ -5062,8 +5080,10 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry...@@ -5062,8 +5080,10 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
5062 return g->builtin_types.entry_invalid;5080 return g->builtin_types.entry_invalid;
5063 } else {5081 } else {
5064 uint64_t size_in_bytes = type_size(g, type_entry);5082 uint64_t size_in_bytes = type_size(g, type_entry);
5083 bool depends_on_compile_var = (type_entry == g->builtin_types.entry_usize ||
5084 type_entry == g->builtin_types.entry_isize);
5065 return resolve_expr_const_val_as_unsigned_num_lit(g, node, expected_type,5085 return resolve_expr_const_val_as_unsigned_num_lit(g, node, expected_type,
5066 size_in_bytes, false);5086 size_in_bytes, depends_on_compile_var);
5067 }5087 }
5068 }5088 }
5069 case BuiltinFnIdAlignof:5089 case BuiltinFnIdAlignof:
...@@ -5461,8 +5481,11 @@ static TypeTableEntry *analyze_fn_call_with_inline_args(CodeGen *g, ImportTableE...@@ -5461,8 +5481,11 @@ static TypeTableEntry *analyze_fn_call_with_inline_args(CodeGen *g, ImportTableE
54615481
5462 ConstExprValue *const_val = &get_resolved_expr(*param_node)->const_val;5482 ConstExprValue *const_val = &get_resolved_expr(*param_node)->const_val;
5463 if (const_val->ok) {5483 if (const_val->ok) {
5464 add_local_var(g, generic_param_decl_node, decl_node->owner, child_context,5484 VariableTableEntry *var = add_local_var(g, generic_param_decl_node, decl_node->owner, child_context,
5465 &generic_param_decl_node->data.param_decl.name, param_type, true, *param_node);5485 &generic_param_decl_node->data.param_decl.name, param_type, true, *param_node);
5486 // This generic function instance could be called with anything, so when this variable is read it
5487 // needs to know that it depends on compile time variable data.
5488 var->force_depends_on_compile_var = true;
5466 } else {5489 } else {
5467 add_node_error(g, *param_node,5490 add_node_error(g, *param_node,
5468 buf_sprintf("unable to evaluate constant expression for inline parameter"));5491 buf_sprintf("unable to evaluate constant expression for inline parameter"));
...@@ -5552,8 +5575,9 @@ static TypeTableEntry *analyze_generic_fn_call(CodeGen *g, ImportTableEntry *imp...@@ -5552,8 +5575,9 @@ static TypeTableEntry *analyze_generic_fn_call(CodeGen *g, ImportTableEntry *imp
55525575
5553 ConstExprValue *const_val = &get_resolved_expr(*param_node)->const_val;5576 ConstExprValue *const_val = &get_resolved_expr(*param_node)->const_val;
5554 if (const_val->ok) {5577 if (const_val->ok) {
5555 add_local_var(g, generic_param_decl_node, decl_node->owner, child_context,5578 VariableTableEntry *var = add_local_var(g, generic_param_decl_node, decl_node->owner, child_context,
5556 &generic_param_decl_node->data.param_decl.name, param_type, true, *param_node);5579 &generic_param_decl_node->data.param_decl.name, param_type, true, *param_node);
5580 var->force_depends_on_compile_var = true;
5557 } else {5581 } else {
5558 add_node_error(g, *param_node, buf_sprintf("unable to evaluate constant expression"));5582 add_node_error(g, *param_node, buf_sprintf("unable to evaluate constant expression"));
55595583
src/codegen.cpp+25
...@@ -1005,6 +1005,31 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {...@@ -1005,6 +1005,31 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {
1005 LLVMBuildStore(g->builder, new_len, dest_len_ptr);1005 LLVMBuildStore(g->builder, new_len, dest_len_ptr);
10061006
10071007
1008 return cast_expr->tmp_ptr;
1009 }
1010 case CastOpBytesToSlice:
1011 {
1012 assert(cast_expr->tmp_ptr);
1013 assert(wanted_type->id == TypeTableEntryIdStruct);
1014 assert(wanted_type->data.structure.is_slice);
1015 assert(actual_type->id == TypeTableEntryIdArray);
1016
1017 TypeTableEntry *wanted_pointer_type = wanted_type->data.structure.fields[0].type_entry;
1018 TypeTableEntry *wanted_child_type = wanted_pointer_type->data.pointer.child_type;
1019
1020 set_debug_source_node(g, node);
1021
1022 int wanted_ptr_index = wanted_type->data.structure.fields[0].gen_index;
1023 LLVMValueRef dest_ptr_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr, wanted_ptr_index, "");
1024 LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, expr_val, wanted_pointer_type->type_ref, "");
1025 LLVMBuildStore(g->builder, src_ptr_casted, dest_ptr_ptr);
1026
1027 int wanted_len_index = wanted_type->data.structure.fields[1].gen_index;
1028 LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr, wanted_len_index, "");
1029 LLVMValueRef len_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref,
1030 actual_type->data.array.len / type_size(g, wanted_child_type), false);
1031 LLVMBuildStore(g->builder, len_val, len_ptr);
1032
1008 return cast_expr->tmp_ptr;1033 return cast_expr->tmp_ptr;
1009 }1034 }
1010 case CastOpIntToFloat:1035 case CastOpIntToFloat:
src/eval.cpp+1
...@@ -601,6 +601,7 @@ void eval_const_expr_implicit_cast(CastOp cast_op,...@@ -601,6 +601,7 @@ void eval_const_expr_implicit_cast(CastOp cast_op,
601 case CastOpPtrToInt:601 case CastOpPtrToInt:
602 case CastOpIntToPtr:602 case CastOpIntToPtr:
603 case CastOpResizeSlice:603 case CastOpResizeSlice:
604 case CastOpBytesToSlice:
604 // can't do it605 // can't do it
605 break;606 break;
606 case CastOpToUnknownSizeArray:607 case CastOpToUnknownSizeArray:
src/parser.cpp+2
...@@ -3301,6 +3301,8 @@ AstNode *ast_clone_subtree_special(AstNode *old_node, uint32_t *next_node_index,...@@ -3301,6 +3301,8 @@ AstNode *ast_clone_subtree_special(AstNode *old_node, uint32_t *next_node_index,
3301 case NodeTypeWhileExpr:3301 case NodeTypeWhileExpr:
3302 clone_subtree_field(&new_node->data.while_expr.condition, old_node->data.while_expr.condition, next_node_index);3302 clone_subtree_field(&new_node->data.while_expr.condition, old_node->data.while_expr.condition, next_node_index);
3303 clone_subtree_field(&new_node->data.while_expr.body, old_node->data.while_expr.body, next_node_index);3303 clone_subtree_field(&new_node->data.while_expr.body, old_node->data.while_expr.body, next_node_index);
3304 clone_subtree_field(&new_node->data.while_expr.continue_expr,
3305 old_node->data.while_expr.continue_expr, next_node_index);
3304 break;3306 break;
3305 case NodeTypeForExpr:3307 case NodeTypeForExpr:
3306 clone_subtree_field(&new_node->data.for_expr.elem_node, old_node->data.for_expr.elem_node, next_node_index);3308 clone_subtree_field(&new_node->data.for_expr.elem_node, old_node->data.for_expr.elem_node, next_node_index);
src/zig_llvm.hpp-1
...@@ -145,7 +145,6 @@ LLVMZigDISubprogram *LLVMZigCreateFunction(LLVMZigDIBuilder *dibuilder, LLVMZigD...@@ -145,7 +145,6 @@ LLVMZigDISubprogram *LLVMZigCreateFunction(LLVMZigDIBuilder *dibuilder, LLVMZigD
145 LLVMZigDIType *fn_di_type, bool is_local_to_unit, bool is_definition, unsigned scope_line,145 LLVMZigDIType *fn_di_type, bool is_local_to_unit, bool is_definition, unsigned scope_line,
146 unsigned flags, bool is_optimized, LLVMZigDISubprogram *decl_subprogram);146 unsigned flags, bool is_optimized, LLVMZigDISubprogram *decl_subprogram);
147147
148
149void ZigLLVMFnSetSubprogram(LLVMValueRef fn, LLVMZigDISubprogram *subprogram);148void ZigLLVMFnSetSubprogram(LLVMValueRef fn, LLVMZigDISubprogram *subprogram);
150149
151void LLVMZigDIBuilderFinalize(LLVMZigDIBuilder *dibuilder);150void LLVMZigDIBuilderFinalize(LLVMZigDIBuilder *dibuilder);
std/rand.zig+129-65
...@@ -1,51 +1,57 @@...@@ -1,51 +1,57 @@
1// Mersenne Twister1const assert = @import("debug.zig").assert;
2const ARRAY_SIZE = 624;2
3pub const MT19937_32 = MersenneTwister(
4 u32, 624, 397, 31,
5 0x9908B0DF,
6 11, 0xFFFFFFFF,
7 7, 0x9D2C5680,
8 15, 0xEFC60000,
9 18, 1812433253);
10
11pub const MT19937_64 = MersenneTwister(
12 u64, 312, 156, 31,
13 0xB5026F5AA96619E9,
14 29, 0x5555555555555555,
15 17, 0x71D67FFFEDA60000,
16 37, 0xFFF7EEE000000000,
17 43, 6364136223846793005);
318
4/// Use `init` to initialize this state.19/// Use `init` to initialize this state.
5pub struct Rand {20pub struct Rand {
6 array: [ARRAY_SIZE]u32,21 const Rng = if (@sizeof(usize) >= 8) MT19937_64 else MT19937_32;
7 index: usize,22
23 rng: Rng,
824
9 /// Initialize random state with the given seed.25 /// Initialize random state with the given seed.
10 #static_eval_enable(false)26 pub fn init(seed: usize) -> Rand {
11 pub fn init(seed: u32) -> Rand {
12 var r: Rand = undefined;27 var r: Rand = undefined;
13 r.index = 0;28 r.rng = Rng.init(seed);
14 r.array[0] = seed;
15 var i : usize = 1;
16 var prev_value: u64w = seed;
17 while (i < ARRAY_SIZE; i += 1) {
18 r.array[i] = @truncate(u32, (prev_value ^ (prev_value << 30)) * 0x6c078965 + u64w(i));
19 prev_value = r.array[i];
20 }
21 return r;29 return r;
22 }30 }
2331
24 /// Get 32 bits of randomness.32 /// Get an integer with random bits.
25 pub fn get_u32(r: &Rand) -> u32 {33 pub fn scalar(r: &Rand, inline T: type) -> T {
26 if (r.index == 0) {34 if (T == usize) {
27 r.generate_numbers();35 return r.rng.get();
36 } else {
37 var result: T = undefined;
38 r.fill_bytes(([]u8)((&result)[0...@sizeof(T)]));
39 return result;
28 }40 }
29
30 // temper the number
31 var y : u32 = r.array[r.index];
32 y ^= y >> 11;
33 y ^= (y >> 7) & 0x9d2c5680;
34 y ^= (y >> 15) & 0xefc60000;
35 y ^= y >> 18;
36
37 r.index = (r.index + 1) % ARRAY_SIZE;
38 return y;
39 }41 }
4042
41 /// Fill `buf` with randomness.43 /// Fill `buf` with randomness.
42 pub fn get_bytes(r: &Rand, buf: []u8) {44 pub fn fill_bytes(r: &Rand, buf: []u8) {
43 var bytes_left = r.get_bytes_aligned(buf);45 var bytes_left = buf.len;
46 while (bytes_left >= @sizeof(usize)) {
47 *((&usize)(&buf[buf.len - bytes_left])) = r.scalar(usize);
48 bytes_left -= @sizeof(usize);
49 }
44 if (bytes_left > 0) {50 if (bytes_left > 0) {
45 var rand_val_array : [@sizeof(u32)]u8 = undefined;51 var rand_val_array : [@sizeof(usize)]u8 = undefined;
46 *((&u32)(&rand_val_array[0])) = r.get_u32();52 ([]usize)(rand_val_array)[0] = r.scalar(usize);
47 while (bytes_left > 0) {53 while (bytes_left > 0) {
48 buf[buf.len - bytes_left] = rand_val_array[@sizeof(u32) - bytes_left];54 buf[buf.len - bytes_left] = rand_val_array[@sizeof(usize) - bytes_left];
49 bytes_left -= 1;55 bytes_left -= 1;
50 }56 }
51 }57 }
...@@ -53,61 +59,119 @@ pub struct Rand {...@@ -53,61 +59,119 @@ pub struct Rand {
5359
54 /// Get a random unsigned integer with even distribution between `start`60 /// Get a random unsigned integer with even distribution between `start`
55 /// inclusive and `end` exclusive.61 /// inclusive and `end` exclusive.
56 pub fn range_u64(r: &Rand, start: u64, end: u64) -> u64 {62 // TODO support signed integers and then rename to "range"
63 pub fn range_unsigned(r: &Rand, inline T: type, start: T, end: T) -> T {
57 const range = end - start;64 const range = end - start;
58 const leftover = @max_value(u64) % range;65 const leftover = @max_value(T) % range;
59 const upper_bound = @max_value(u64) - leftover;66 const upper_bound = @max_value(T) - leftover;
60 var rand_val_array : [@sizeof(u64)]u8 = undefined;67 var rand_val_array : [@sizeof(T)]u8 = undefined;
6168
62 while (true) {69 while (true) {
63 r.get_bytes_aligned(rand_val_array);70 r.fill_bytes(rand_val_array);
64 const rand_val = *(&u64)(&rand_val_array[0]);71 const rand_val = ([]T)(rand_val_array)[0];
65 if (rand_val < upper_bound) {72 if (rand_val < upper_bound) {
66 return start + (rand_val % range);73 return start + (rand_val % range);
67 }74 }
68 }75 }
69 }76 }
7077
71 pub fn float32(r: &Rand) -> f32 {78 /// Get a floating point value in the range 0.0..1.0.
72 const precision = 16777216;79 pub fn float(r: &Rand, inline T: type) -> T {
73 return f32(r.range_u64(0, precision)) / precision;80 const int_type = @int_type(false, @sizeof(T) * 8, false);
81 // TODO switch statement for constant values
82 const precision = if (T == f32) {
83 16777216
84 } else if (T == f64) {
85 9007199254740992
86 } else {
87 @compile_err("unknown floating point type" ++ @type_name(T))
88 };
89 return T(r.range_unsigned(int_type, 0, precision)) / T(precision);
74 }90 }
91}
92
93struct MersenneTwister(
94 int: type, n: usize, m: usize, r: int,
95 a: int,
96 u: int, d: int,
97 s: int, b: int,
98 t: int, c: int,
99 l: int, f: int)
100{
101 const Self = MersenneTwister(int, n, m, r, a, u, d, s, b, t, c, l, f);
102 const intw = @int_type(int.is_signed, int.bit_count, true);
103
104 array: [n]int,
105 index: usize,
106
107 // TODO improve compile time eval code and then allow this function to be executed at compile time.
108 #static_eval_enable(false)
109 pub fn init(seed: int) -> Self {
110 var mt = Self {
111 .index = n,
112 .array = undefined,
113 };
114
115 var prev_value = seed;
116 mt.array[0] = prev_value;
117 {var i: usize = 1; while (i < n; i += 1) {
118 prev_value = intw(i) + intw(f) * intw(prev_value ^ (prev_value >> (int.bit_count - 2)));
119 mt.array[i] = prev_value;
120 }};
75121
76 pub fn boolean(r: &Rand) -> bool {122 return mt;
77 return (r.get_u32() & 0x1) == 1;
78 }123 }
79124
80 fn generate_numbers(r: &Rand) {125 pub fn get(mt: &Self) -> int {
81 for (r.array) |item, i| {126 const mag01 = []int{0, a};
82 const y : u32 = (item & 0x80000000) + (r.array[(i + 1) % ARRAY_SIZE] & 0x7fffffff);127 const LM: int = (1 << r) - 1;
83 const untempered : u32 = r.array[(i + 397) % ARRAY_SIZE] ^ (y >> 1);128 const UM = ~LM;
84 r.array[i] = if ((y % 2) == 0) {129
85 untempered130 if (int.bit_count == 64) {
86 } else {131 assert(LM == 0x7fffffff);
87 // y is odd132 assert(UM == 0xffffffff80000000);
88 untempered ^ 0x9908b0df133 } else if (int.bit_count == 32) {
89 };134 assert(LM == 0x7fffffff);
135 assert(UM == 0x80000000);
90 }136 }
91 }
92137
93 // does not populate the remaining (buf.len % 4) bytes138 if (mt.index >= n) {
94 fn get_bytes_aligned(r: &Rand, buf: []u8) -> usize {139 var i: usize = 0;
95 var bytes_left = buf.len;140
96 while (bytes_left >= 4) {141 while (i < n - m; i += 1) {
97 *((&u32)(&buf[buf.len - bytes_left])) = r.get_u32();142 const x = (mt.array[i] & UM) | (mt.array[i + 1] & LM);
98 bytes_left -= @sizeof(u32);143 mt.array[i] = mt.array[i + m] ^ (x >> 1) ^ mag01[x & 0x1];
144 }
145
146 while (i < n - 1; i += 1) {
147 const x = (mt.array[i] & UM) | (mt.array[i + 1] & LM);
148 mt.array[i] = mt.array[i + m - n] ^ (x >> 1) ^ mag01[x & 0x1];
149
150 }
151 const x = (mt.array[i] & UM) | (mt.array[0] & LM);
152 mt.array[i] = mt.array[m - 1] ^ (x >> 1) ^ mag01[x & 0x1];
153
154 mt.index = 0;
99 }155 }
100 return bytes_left;
101 }
102156
157 var x: intw = mt.array[mt.index];
158 mt.index += 1;
159
160 x ^= ((x >> u) & d);
161 x ^= ((x << s) & b);
162 x ^= ((x << t) & c);
163 x ^= (x >> l);
164
165 return x;
166 }
103}167}
104168
105#attribute("test")169#attribute("test")
106fn test_float32() {170fn test_float32() {
107 var r = Rand.init(42);171 var r = Rand.init(42);
108172
109 {var i: i32 = 0; while (i < 1000; i += 1) {173 {var i: usize = 0; while (i < 1000; i += 1) {
110 const val = r.float32();174 const val = r.float(f32);
111 if (!(val >= 0.0)) unreachable{};175 if (!(val >= 0.0)) unreachable{};
112 if (!(val < 1.0)) unreachable{};176 if (!(val < 1.0)) unreachable{};
113 }}177 }}
test/run_tests.cpp+6
...@@ -1427,6 +1427,12 @@ export inline fn foo(x: i32, y: i32) -> i32{...@@ -1427,6 +1427,12 @@ export inline fn foo(x: i32, y: i32) -> i32{
1427 )SOURCE", 1, ".tmp_source.zig:2:1: error: extern functions cannot be inline");1427 )SOURCE", 1, ".tmp_source.zig:2:1: error: extern functions cannot be inline");
1428 */1428 */
14291429
1430 add_compile_fail_case("convert fixed size array to slice with invalid size", R"SOURCE(
1431fn f() {
1432 var array: [5]u8 = undefined;
1433 var foo = ([]u32)(array)[0];
1434}
1435 )SOURCE", 1, ".tmp_source.zig:4:22: error: unable to convert [5]u8 to []u32: size mismatch");
1430}1436}
14311437
1432//////////////////////////////////////////////////////////////////////////////1438//////////////////////////////////////////////////////////////////////////////