Merge branch 'main' into make-threading-mathier

This commit is contained in:
Chris Boesch
2026-06-30 00:09:19 +02:00
18 changed files with 159 additions and 87 deletions
+16 -2
View File
@@ -26,8 +26,13 @@ pub fn main() void {
// (Problem 2)
// Please set this array using repetition.
// It should result in: 1 0 0 1 1 0 0 1 1 0 0 1
const bit_pattern_unit = [_]u8{ ??? };
const bit_pattern: [3 * bit_pattern_unit.len]u8 = @bitCast(@as([3][bit_pattern_unit.len]u8, @splat(bit_pattern_unit)));
const bit_pattern_unit = ???;
// How long should the bit pattern be?
const len = ???;
// For now, don't worry about the use of SIMD.
const bit_pattern: [len]u8 = std.simd.repeat(len, bit_pattern_unit);
// Okay, that's all of the problems. Let's see the results.
//
@@ -53,3 +58,12 @@ pub fn main() void {
std.debug.print("\n", .{});
}
// For the curious:
//
// The `std.simd.repeat` function takes a target length and a pattern,
// and returns a vector filled with that pattern repeated to the
// desired length.
//
// For example, `repeat(5, [_]u8{1, 2})` will return a vector
// equivalent to `.{1, 2, 1, 2, 1}`.
+1 -1
View File
@@ -1,6 +1,6 @@
//
// As with integers, you can pass a pointer to a struct when you
// will wish to modify that struct. Pointers are also useful when
// wish to modify that struct. Pointers are also useful when
// you need to store a reference to a struct (a "link" to it).
//
// const Vertex = struct{ x: u32, y: u32, z: u32 };
+18
View File
@@ -37,6 +37,24 @@
// self, others use a lowercase version of the type name, but feel
// free to use whatever is most appropriate.
//
// "But hold on," you say, eyeing a() and b() suspiciously, "why
// does one take 'self' and another take '*self'?" Sharp eye!
//
// It all comes down to a single question: does the function need
// to CHANGE the struct?
//
// * Needs to change it? Take a pointer (*Bar). Without it you'd
// be scribbling on a COPY, and your changes would evaporate the
// instant the function returns. Poof.
// * Only reads it? Plain Bar is just fine.
// (For a big, bulky struct you might still write *const Bar to
// avoid copying it around, but for small ones a copy is cheap.)
//
// You'll see this below: zap() takes 'self: HeatRay' by value
// because it only reads the ray's damage, but it takes the alien
// as '*Alien' because zapping is supposed to HURT - and that means
// changing the alien's health for real, not on a throwaway copy.
//
// Okay, you're armed.
//
// Now, please zap the alien structs until they're all gone or
+3 -3
View File
@@ -47,7 +47,7 @@ const Narcissus = struct {
myself: *Narcissus = undefined,
echo: void = undefined, // Alas, poor Echo!
fn fetchTheMostBeautifulType() type {
fn FetchTheMostBeautifulType() type {
return @This();
}
};
@@ -70,7 +70,7 @@ pub fn main() void {
//
// The fix for this is very subtle, but it makes a big
// difference!
const Type2 = narcissus.fetchTheMostBeautifulType();
const Type2 = narcissus.FetchTheMostBeautifulType();
// Now we print a pithy statement about Narcissus.
print("A {s} loves all {s}es. ", .{
@@ -94,7 +94,7 @@ pub fn main() void {
print("He has room in his heart for:", .{});
// `field_names` is a slice of strings and it holds the names of the struct's fields
// `field_types` is a slice of strings and it holds the types of the struct's fields,
// `field_types` is a slice of types and it holds the types of the struct's fields,
// it is guaranteed to be the same length as `field_names`
const field_names = @typeInfo(Narcissus).@"struct".field_names;
const field_types = @typeInfo(Narcissus).@"struct".field_types;
+7 -8
View File
@@ -1,5 +1,5 @@
//
// In Exercises 84-91, we learned about Zig's Io interface for
// In Exercises 85-94 and quiz 95, we learned about Zig's Io interface for
// concurrent execution: io.async(), Group, Select, and Futures.
// Under the hood, the Threaded backend manages a pool of real
// OS threads for you - including scheduling, cancellation, and
@@ -74,11 +74,11 @@ pub fn main() !void {
// before the parallel processing begins.
std.debug.print("Starting work...\n", .{});
// These curly brackets are very important, they are necessary
// to enclose the area where the threads are called.
// Without these brackets, the program would not wait for the
// end of the threads and they would continue to run beyond the
// end of the program.
// These curly braces are very important, they are necessary
// to enclose the area where the threads are called and joined.
// With these braces, the program will block and wait for all threads
// to finish right at the closing brace of this block, ensuring
// "Zig is cool!" is always printed last.
{
// Now we start the first thread, with the number as parameter
const handle = try std.Thread.spawn(.{}, thread_function, .{1});
@@ -102,8 +102,7 @@ pub fn main() !void {
try io.sleep(std.Io.Duration.fromMilliseconds(400), .awake);
std.debug.print("Some weird stuff, after starting the threads.\n", .{});
}
// After we have left the closed area, we wait until
// the threads have run through, if this has not yet been the case.
// The threads are guaranteed to be finished by the time we reach here.
std.debug.print("Zig is cool!\n", .{});
}
+1 -1
View File
@@ -46,7 +46,7 @@
// 1,000,000,000 partial values. And for each additional digit we have to
// add a zero.
// Even fast computers - and I mean really fast computers - get a bit warmer
// on the CPU when it comes to really many digits. But the 8 digits are
// on the CPU when it comes to a large number of digits. But 8 digits are
// enough for us for now, because we want to understand the principle and
// nothing more, right?
//
+1 -1
View File
@@ -50,7 +50,7 @@ pub fn main(init: std.process.Init) !void {
// wait a minute...
// opening a directory might fail!
// what should we do here?
var output_dir: std.Io.Dir = try cwd.openDir(io, "output", .{});
var output_dir: std.Io.Dir = cwd.openDir(io, "output", .{});
defer output_dir.close(io);
// we try to open the file `zigling.txt`,
+4
View File
@@ -145,3 +145,7 @@ pub fn main() void {
print("Max difference (old fn): {d: >5.3}\n", .{mpd_old});
print("Max difference (new fn): {d: >5.3}\n", .{mpd_new});
}
// Another cool feature of Vectors is repeating patterns.
// Remember the arrays exercise from earlier where we created an array
// by repeating a pattern? See `005_arrays2.zig`.
+1 -1
View File
@@ -14,7 +14,7 @@
//
// A common activity in microcontroller programming is setting and clearing
// bits on input and output pins. This lets you control LEDs, sensors, motors
// and more! In a previous exercise (097_bit_manipulation.zig) you learned how
// and more! In a previous exercise (100_bit_manipulation.zig) you learned how
// to swap two bytes using the ^ (XOR - exclusive or) operator. This quiz will
// test your knowledge of bit manipulation in Zig while giving you a taste of
// what it's like to control registers in a real microcontroller. Included at
+2 -2
View File
@@ -1,6 +1,6 @@
//
// We've already learned plenty about bit manipulation using bitwise operations
// in exercises 097 and 098 and in quiz 110. The techniques we already know work
// in exercises 100 and 101 and in quiz 113. The techniques we already know work
// just fine, but creating masks and shifting individual bits around can become
// quite tedious and unwieldy pretty quickly.
// What if there was a better, a more convenient way to control individual bits?
@@ -78,7 +78,7 @@ const FLG = packed struct(u8) {
content_checksum: bool,
content_size: bool,
block_checksum: bool,
block_indepencence: bool,
block_independence: bool,
version: u2,
};
+3 -3
View File
@@ -1,5 +1,5 @@
//
// We've already learned about switch statements in exercises 030, 031 and 108.
// We've already learned about switch statements in exercises 030, 031 and 111.
// They also work with packed containers:
const S = packed struct(u2) {
@@ -51,11 +51,11 @@ comptime {
//
// Try to make the float below negative:
/// IEEE 754 half precision float
// IEEE 754 binary16 floating-point format
const Float = packed union(u16) {
value: f16,
bits: packed struct(u16) {
mantissa: u10,
significand: u10,
exponent: u5,
sign: u1,
},