From 9e48c9a339cde73fb7477f252e98efe0fc6d8de0 Mon Sep 17 00:00:00 2001 From: Chris Boesch Date: Wed, 28 Feb 2024 13:01:11 +0100 Subject: [PATCH 01/13] Added notes to exercise 94 c_math. --- exercises/094_c_math.zig | 23 +++++++++++++++-------- patches/patches/094_c_math.patch | 6 +++--- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/exercises/094_c_math.zig b/exercises/094_c_math.zig index e650f6e..61e2c7b 100644 --- a/exercises/094_c_math.zig +++ b/exercises/094_c_math.zig @@ -1,19 +1,26 @@ // // Often, C functions are used where no equivalent Zig function exists -// yet. Since the integration of a C function is very simple, as already +// yet. Okay, that's getting less and less. ;-) +// +// Since the integration of a C function is very simple, as already // seen in the last exercise, it naturally offers itself to use the // very large variety of C functions for our own programs. // As an example: // // Let's say we have a given angle of 765.2 degrees. If we want to // normalize that, it means that we have to subtract X * 360 degrees -// to get the correct angle. How could we do that? A good method is -// to use the modulo function. But if we write "765.2 % 360", it won't -// work, because the standard modulo function works only with integer -// values. In the C library "math", there is a function called "fmod"; -// the "f" stands for floating and means that we can solve modulo for -// real numbers. With this function, it should be possible to normalize -// our angle. Let's go. +// to get the correct angle. +// How could we do that? A good method is to use the modulo function. +// But if we write "765.2 % 360", it only works with float values +// that are known at compile time. +// In Zig, we would use %mod(a, b) instead. +// +// Let us now assume that we cannot do this in Zig, but only with +// a C function from the standard library. In the library "math", +// there is a function called "fmod"; the "f" stands for floating +// and means that we can solve modulo for real numbers. With this +// function, it should be possible to normalize our angle. +// Let's go. const std = @import("std"); diff --git a/patches/patches/094_c_math.patch b/patches/patches/094_c_math.patch index 67da7e8..f8c7620 100644 --- a/patches/patches/094_c_math.patch +++ b/patches/patches/094_c_math.patch @@ -1,6 +1,6 @@ ---- exercises/094_c_math.zig 2023-10-22 14:00:02.909379696 +0200 -+++ answers/094_c_math.zig 2023-10-22 14:02:46.709025235 +0200 -@@ -19,7 +19,7 @@ +--- exercises/094_c_math.zig 2024-02-28 12:50:35.789939935 +0100 ++++ answers/094_c_math.zig 2024-02-28 12:53:57.910309471 +0100 +@@ -26,7 +26,7 @@ const c = @cImport({ // What do we need here? From 6984345d0af6fb88438ad260fb9146bc8c36466b Mon Sep 17 00:00:00 2001 From: Chris Boesch Date: Tue, 5 Mar 2024 09:15:57 +0100 Subject: [PATCH 02/13] Added threading exercise --- README.md | 1 + build.zig | 14 +++ exercises/104_threading.zig | 129 ++++++++++++++++++++++++++++ patches/patches/104_threading.patch | 17 ++++ 4 files changed, 161 insertions(+) create mode 100644 exercises/104_threading.zig create mode 100644 patches/patches/104_threading.patch diff --git a/README.md b/README.md index ba7ffa8..44476e8 100644 --- a/README.md +++ b/README.md @@ -216,6 +216,7 @@ Zig Core Language * [X] Interfaces * [X] Bit manipulation * [X] Working with C +* [X] Threading * [ ] Interfaces part 2 Zig Standard Library diff --git a/build.zig b/build.zig index 71ea66f..5263023 100644 --- a/build.zig +++ b/build.zig @@ -1103,6 +1103,20 @@ const exercises = [_]Exercise{ \\This little poem has 15 words! , }, + .{ + .main_file = "104_threading.zig", + .output = + \\Starting work... + \\thread 1: started. + \\thread 2: started. + \\thread 3: started. + \\Some weird stuff, after starting the threads. + \\thread 2: finished. + \\thread 1: finished. + \\thread 3: finished. + \\Zig is cool! + , + }, .{ .main_file = "999_the_end.zig", .output = diff --git a/exercises/104_threading.zig b/exercises/104_threading.zig new file mode 100644 index 0000000..8aeb683 --- /dev/null +++ b/exercises/104_threading.zig @@ -0,0 +1,129 @@ +// +// Whenever there is a lot to calculate, the question arises as to how +// tasks can be carried out simultaneously. We have already learned about +// one possibility, namely asynchronous processes, in Exercises 84-91. +// +// However, the computing power of the processor is only distributed to +// the started tasks, which always reaches its limits when pure computing +// power is called up. +// +// For example, in blockchains based on proof of work, the miners have +// to find a nonce for a certain character string so that the first m bits +// in the hash of the character string and the nonce are zeros. +// As the miner who can solve the task first receives the reward, everyone +// tries to complete the calculations as quickly as possible. +// +// This is where multithreading comes into play, where tasks are actually +// distributed across several cores of the CPU or GPU, which then really +// means a multiplication of performance. +// +// The following diagram roughly illustrates the difference between the +// various types of process execution. +// The 'Overall Time' column is intended to illustrate how the time is +// affected if, instead of one core as in synchronous and asynchronous +// processing, a second core now helps to complete the work in multithreading. +// +// In the ideal case shown, execution takes only half the time compared +// to the synchronous single thread. And even asynchronous processing +// is only slightly faster in comparison. +// +// +// Synchronous Asynchronous +// Processing Processing Multithreading +// ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ +// │ Thread 1 │ │ Thread 1 │ │ Thread 1 │ │ Thread 2 │ +// ├──────────┤ ├──────────┤ ├──────────┤ ├──────────┤ Overall Time +// └──┼┼┼┼┼───┴─┴──┼┼┼┼┼───┴──┴──┼┼┼┼┼───┴─┴──┼┼┼┼┼───┴──┬───────┬───────┬── +// ├───┤ ├───┤ ├───┤ ├───┤ │ │ │ +// │ T │ │ T │ │ T │ │ T │ │ │ │ +// │ a │ │ a │ │ a │ │ a │ │ │ │ +// │ s │ │ s │ │ s │ │ s │ │ │ │ +// │ k │ │ k │ │ k │ │ k │ │ │ │ +// │ │ │ │ │ │ │ │ │ │ │ +// │ 1 │ │ 1 │ │ 1 │ │ 3 │ │ │ │ +// └─┬─┘ └─┬─┘ └─┬─┘ └─┬─┘ │ │ │ +// │ │ │ │ 5 Sec │ │ +// ┌────┴───┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ │ │ │ +// │Blocking│ │ T │ │ T │ │ T │ │ │ │ +// └────┬───┘ │ a │ │ a │ │ a │ │ │ │ +// │ │ s │ │ s │ │ s │ │ 8 Sec │ +// ┌─┴─┐ │ k │ │ k │ │ k │ │ │ │ +// │ T │ │ │ │ │ │ │ │ │ │ +// │ a │ │ 2 │ │ 2 │ │ 4 │ │ │ │ +// │ s │ └─┬─┘ ├───┤ ├───┤ │ │ │ +// │ k │ │ │┼┼┼│ │┼┼┼│ ▼ │ 10 Sec +// │ │ ┌─┴─┐ └───┴────────┴───┴───────── │ │ +// │ 1 │ │ T │ │ │ +// └─┬─┘ │ a │ │ │ +// │ │ s │ │ │ +// ┌─┴─┐ │ k │ │ │ +// │ T │ │ │ │ │ +// │ a │ │ 1 │ │ │ +// │ s │ ├───┤ │ │ +// │ k │ │┼┼┼│ ▼ │ +// │ │ └───┴──────────────────────────────────────────── │ +// │ 2 │ │ +// ├───┤ │ +// │┼┼┼│ ▼ +// └───┴──────────────────────────────────────────────────────────────── +// +// +// The diagram was modeled on the one in a blog in which the differences +// between asynchronous processing and multithreading are explained in detail: +// https://blog.devgenius.io/multi-threading-vs-asynchronous-programming-what-is-the-difference-3ebfe1179a5 +// +// Our exercise is essentially about clarifying the approach in Zig and +// therefore we try to keep it as simple as possible. +// Multithreading in itself is already difficult enough. ;-) +// +const std = @import("std"); + +pub fn main() !void { + // This is where the preparatory work takes place + // 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. + { + // Now we start the first thread, with the number as parameter + const handle = try std.Thread.spawn(.{}, thread_function, .{1}); + + // Waits for the thread to complete, + // then deallocates any resources created on `spawn()`. + defer handle.join(); + + // Second thread + const handle2 = try std.Thread.spawn(.{}, thread_function, .{-4}); // that can't be right? + defer handle2.join(); + + // Third thread + const handle3 = try std.Thread.spawn(.{}, thread_function, .{3}); + defer ??? // <-- something is missing + + // After the threads have been started, + // they run in parallel and we can still do some work in between. + std.time.sleep((1) * std.time.ns_per_s); + 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. + std.debug.print("Zig is cool!\n", .{}); +} + +// This function is started with every thread that we set up. +// In our example, we pass the number of the thread as a parameter. +fn thread_function(num: usize) !void { + std.debug.print("thread {d}: {s}\n", .{ num, "started." }); + std.time.sleep((5 - num % 3) * std.time.ns_per_s); + std.debug.print("thread {d}: {s}\n", .{ num, "finished." }); +} +// This is the easiest way to run threads in parallel. +// In general, however, more management effort is required, +// e.g. by setting up a pool and allowing the threads to communicate +// with each other using semaphores. +// +// But that's a topic for another exercise. diff --git a/patches/patches/104_threading.patch b/patches/patches/104_threading.patch new file mode 100644 index 0000000..58410a8 --- /dev/null +++ b/patches/patches/104_threading.patch @@ -0,0 +1,17 @@ +--- exercises/104_threading.zig 2024-03-05 09:09:04.013974229 +0100 ++++ answers/104_threading.zig 2024-03-05 09:12:03.987162883 +0100 +@@ -97,12 +97,12 @@ + defer handle.join(); + + // Second thread +- const handle2 = try std.Thread.spawn(.{}, thread_function, .{-4}); // that can't be right? ++ const handle2 = try std.Thread.spawn(.{}, thread_function, .{2}); + defer handle2.join(); + + // Third thread + const handle3 = try std.Thread.spawn(.{}, thread_function, .{3}); +- defer ??? // <-- something is missing ++ defer handle3.join(); + + // After the threads have been started, + // they run in parallel and we can still do some work in between. From d0519d18fade9d099f4737f4e4c6ade976c2a685 Mon Sep 17 00:00:00 2001 From: Chris Boesch Date: Fri, 8 Mar 2024 01:07:57 +0100 Subject: [PATCH 03/13] Fixed unicode literal --- exercises/059_integers.zig | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/exercises/059_integers.zig b/exercises/059_integers.zig index 39e077c..ae65790 100644 --- a/exercises/059_integers.zig +++ b/exercises/059_integers.zig @@ -2,12 +2,12 @@ // Zig lets you express integer literals in several convenient // formats. These are all the same value: // -// const a1: u8 = 65; // decimal -// const a2: u8 = 0x41; // hexadecimal -// const a3: u8 = 0o101; // octal -// const a4: u8 = 0b1000001; // binary -// const a5: u8 = 'A'; // ASCII code point literal -// const a6: u16 = 'Ȁ'; // Unicode code points can take up to 21 bits +// const a1: u8 = 65; // decimal +// const a2: u8 = 0x41; // hexadecimal +// const a3: u8 = 0o101; // octal +// const a4: u8 = 0b1000001; // binary +// const a5: u8 = 'A'; // ASCII code point literal +// const a6: u16 = '\u{0041}'; // Unicode code points can take up to 21 bits // // You can also place underscores in numbers to aid readability: // From 08cc60ba59774e16c2fe0a6327a10c44022b1766 Mon Sep 17 00:00:00 2001 From: Chris Boesch Date: Tue, 12 Mar 2024 20:59:29 +0100 Subject: [PATCH 04/13] Minor corrections to the "contributing" --- CONTRIBUTING.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 64b308e..bb43f67 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -54,13 +54,12 @@ Ziglings. Please file an issue...or make a pull request! ## Formatting -All exercises should conform to `zig fmt`. I often forget to do -this. +All exercises should conform to `zig fmt`. ## Pull Request Workflow -Ziglings uses the "standard" Github workflow as guided by the Web +Ziglings uses the "standard" Codeberg workflow as guided by the Web interface. Specifically: * Fork this repository @@ -71,7 +70,7 @@ interface. Specifically: `git push origin my-branch` * Create a pull request from your branch to `ziglings/main` * Your faithful Ziglings maintainers will take a look at your - request ASAP (we don't talk about May-July 2022, LOL) + request ASAP (we don't talk about May-July, LOL) * Once the changes are reviewed, your request will be merged and eternal Ziglings contributor glory is yours! From c8f081f3e8f76efa53c63d2d12ad5d19147d0c28 Mon Sep 17 00:00:00 2001 From: dolichomps Date: Thu, 14 Mar 2024 02:28:07 +0000 Subject: [PATCH 05/13] fix exercise 82 output zig commit bd24e66 changed the floating point formatting implementation so output for exercise 82 no longer matched --- build.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.zig b/build.zig index 5263023..a612a23 100644 --- a/build.zig +++ b/build.zig @@ -939,7 +939,7 @@ const exercises = [_]Exercise{ .{ .main_file = "082_anonymous_structs3.zig", .output = - \\"0"(bool):true "1"(bool):false "2"(i32):42 "3"(f32):3.14159202e+00 + \\"0"(bool):true "1"(bool):false "2"(i32):42 "3"(f32):3.141592e0 , .hint = "This one is a challenge! But you have everything you need.", }, From 9844123dd1b3cdc0c1a94602eb3569a9119cccae Mon Sep 17 00:00:00 2001 From: Chris Boesch Date: Thu, 14 Mar 2024 23:37:14 +0100 Subject: [PATCH 06/13] Improved the explanation about passing arguments and added an example. --- exercises/051_values.zig | 17 ++++++++++++++--- patches/patches/051_values.patch | 6 +++--- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/exercises/051_values.zig b/exercises/051_values.zig index f2653f9..4e98d8e 100644 --- a/exercises/051_values.zig +++ b/exercises/051_values.zig @@ -141,9 +141,20 @@ pub fn main() void { // // Moving along... // - // Passing arguments to functions is pretty much exactly like - // making an assignment to a const (since Zig enforces that ALL - // function parameters are const). + // When arguments are passed to a function, + // they are ALWAYS passed as constants within the function, + // regardless of how they were declared in the calling function. + // + // Example: + // fn foo(arg: u8) void { + // arg = 42; // Error, 'arg' is const! + // } + // + // fn bar() void { + // var arg: u8 = 12; + // foo(arg); + // ... + // } // // Knowing this, see if you can make levelUp() work as expected - // it should add the specified amount to the supplied character's diff --git a/patches/patches/051_values.patch b/patches/patches/051_values.patch index bb65525..53d73be 100644 --- a/patches/patches/051_values.patch +++ b/patches/patches/051_values.patch @@ -1,5 +1,5 @@ ---- exercises/051_values.zig 2023-10-03 22:15:22.122241138 +0200 -+++ answers/051_values.zig 2023-10-05 20:04:07.072767194 +0200 +--- exercises/051_values.zig 2024-03-14 23:25:42.695020607 +0100 ++++ answers/051_values.zig 2024-03-14 23:28:34.525109174 +0100 @@ -87,7 +87,7 @@ // Let's assign the std.debug.print function to a const named // "print" so that we can use this new name later! @@ -9,7 +9,7 @@ // Now let's look at assigning and pointing to values in Zig. // -@@ -152,13 +152,13 @@ +@@ -163,13 +163,13 @@ print("XP before:{}, ", .{glorp.experience}); // Fix 1 of 2 goes here: From abed92c05ed3a541c6dd4e026bc0ce47cbdb0542 Mon Sep 17 00:00:00 2001 From: Chris Boesch Date: Thu, 14 Mar 2024 23:59:13 +0100 Subject: [PATCH 07/13] Changes for a new Zig version. --- README.md | 3 ++- build.zig | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 44476e8..830f5eb 100644 --- a/README.md +++ b/README.md @@ -96,7 +96,8 @@ that if you update one, you may need to also update the other. ### Version Changes -Version-0.12.0-dev.2618 +Version-0.12.0-dev.3302 +* *2024-03-14* zig 0.12.0-dev.3302 - changes in `std.fmt` - floating-point formatting implementation - see[#19229](https://github.com/ziglang/zig/pull/19229) * *2024-02-05* zig 0.12.0-dev.2618 - changes in `build system` - from `Step.zig_exe` to `Step.graph.zig_exe` - see[#18778](https://github.com/ziglang/zig/issues/18778) * *2024-01-05* zig 0.12.0-dev.2043 - rename of `std.Build.FileSource` to `std.Build.LazyPath` - see[#16353](https://github.com/ziglang/zig/issues/16353) * *2023-10-24* zig 0.12.0-dev.1243 - changes in `std.ChildProcess`: renamed exec to run - see[#5853](https://github.com/ziglang/zig/issues/5853) diff --git a/build.zig b/build.zig index a612a23..1101773 100644 --- a/build.zig +++ b/build.zig @@ -15,7 +15,7 @@ const print = std.debug.print; // 1) Getting Started // 2) Version Changes comptime { - const required_zig = "0.12.0-dev.2618"; + const required_zig = "0.12.0-dev.3302"; const current_zig = builtin.zig_version; const min_zig = std.SemanticVersion.parse(required_zig) catch unreachable; if (current_zig.order(min_zig) == .lt) { From 2b9e3da5c8f0568c5c5de1f03754f739339b13fa Mon Sep 17 00:00:00 2001 From: Chris Boesch Date: Fri, 22 Mar 2024 00:25:01 +0100 Subject: [PATCH 08/13] Fixed the renaming of std.os to std.posix --- README.md | 11 ++++++----- build.zig | 10 +++++----- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 830f5eb..8a26c1c 100644 --- a/README.md +++ b/README.md @@ -96,11 +96,12 @@ that if you update one, you may need to also update the other. ### Version Changes -Version-0.12.0-dev.3302 -* *2024-03-14* zig 0.12.0-dev.3302 - changes in `std.fmt` - floating-point formatting implementation - see[#19229](https://github.com/ziglang/zig/pull/19229) -* *2024-02-05* zig 0.12.0-dev.2618 - changes in `build system` - from `Step.zig_exe` to `Step.graph.zig_exe` - see[#18778](https://github.com/ziglang/zig/issues/18778) -* *2024-01-05* zig 0.12.0-dev.2043 - rename of `std.Build.FileSource` to `std.Build.LazyPath` - see[#16353](https://github.com/ziglang/zig/issues/16353) -* *2023-10-24* zig 0.12.0-dev.1243 - changes in `std.ChildProcess`: renamed exec to run - see[#5853](https://github.com/ziglang/zig/issues/5853) +Version-0.12.0-dev.3397 +* *2024-03-21* zig 0.12.0-dev.3397 - rename std.os to std.posix - see [#5019](https://github.com/ziglang/zig/issues/5019) +* *2024-03-14* zig 0.12.0-dev.3302 - changes in `std.fmt` - floating-point formatting implementation - see [#19229](https://github.com/ziglang/zig/pull/19229) +* *2024-02-05* zig 0.12.0-dev.2618 - changes in `build system` - from `Step.zig_exe` to `Step.graph.zig_exe` - see [#18778](https://github.com/ziglang/zig/issues/18778) +* *2024-01-05* zig 0.12.0-dev.2043 - rename of `std.Build.FileSource` to `std.Build.LazyPath` - see [#16353](https://github.com/ziglang/zig/issues/16353) +* *2023-10-24* zig 0.12.0-dev.1243 - changes in `std.ChildProcess`: renamed exec to run - see [#5853](https://github.com/ziglang/zig/issues/5853) * *2023-06-26* zig 0.11.0-dev.4246 - changes in compile step (now it can be null) * *2023-06-26* zig 0.11.0-dev.3853 - removal of destination type from all cast builtins * *2023-06-20* zig 0.11.0-dev.3747 - `@enumToInt` is now `@intFromEnum` and `@intToFloat` is now `@floatFromInt` diff --git a/build.zig b/build.zig index 1101773..b90703b 100644 --- a/build.zig +++ b/build.zig @@ -15,7 +15,7 @@ const print = std.debug.print; // 1) Getting Started // 2) Version Changes comptime { - const required_zig = "0.12.0-dev.3302"; + const required_zig = "0.12.0-dev.3397"; const current_zig = builtin.zig_version; const min_zig = std.SemanticVersion.parse(required_zig) catch unreachable; if (current_zig.order(min_zig) == .lt) { @@ -119,7 +119,7 @@ pub const logo = ; pub fn build(b: *Build) !void { - if (!validate_exercises()) std.os.exit(2); + if (!validate_exercises()) std.process.exit(2); use_color_escapes = false; if (std.io.getStdErr().supportsAnsiEscapeCodes()) { @@ -172,7 +172,7 @@ pub fn build(b: *Build) !void { // Named build mode: verifies a single exercise. if (n == 0 or n > exercises.len - 1) { print("unknown exercise number: {}\n", .{n}); - std.os.exit(2); + std.process.exit(2); } const ex = exercises[n - 1]; @@ -262,7 +262,7 @@ const ZiglingStep = struct { print("\n{s}Ziglings hint: {s}{s}", .{ bold_text, hint, reset_text }); self.help(); - std.os.exit(2); + std.process.exit(2); }; self.run(exe_path.?, prog_node) catch { @@ -272,7 +272,7 @@ const ZiglingStep = struct { print("\n{s}Ziglings hint: {s}{s}", .{ bold_text, hint, reset_text }); self.help(); - std.os.exit(2); + std.process.exit(2); }; // Print possible warning/debug messages. From d65e3f3f9a42d9eb1695e50763b2a81f745f5596 Mon Sep 17 00:00:00 2001 From: Chris Boesch Date: Sat, 23 Mar 2024 16:42:27 +0100 Subject: [PATCH 09/13] Added second threading exercise. --- README.md | 1 - build.zig | 4 + exercises/105_threading2.zig | 107 +++++++++++++++++++++++++++ patches/patches/105_threading2.patch | 13 ++++ 4 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 exercises/105_threading2.zig create mode 100644 patches/patches/105_threading2.patch diff --git a/README.md b/README.md index 8a26c1c..d7945a7 100644 --- a/README.md +++ b/README.md @@ -219,7 +219,6 @@ Zig Core Language * [X] Bit manipulation * [X] Working with C * [X] Threading -* [ ] Interfaces part 2 Zig Standard Library diff --git a/build.zig b/build.zig index b90703b..8319bb4 100644 --- a/build.zig +++ b/build.zig @@ -1117,6 +1117,10 @@ const exercises = [_]Exercise{ \\Zig is cool! , }, + .{ + .main_file = "105_threading2.zig", + .output = "PI ≈ 3.14159265", + }, .{ .main_file = "999_the_end.zig", .output = diff --git a/exercises/105_threading2.zig b/exercises/105_threading2.zig new file mode 100644 index 0000000..a211551 --- /dev/null +++ b/exercises/105_threading2.zig @@ -0,0 +1,107 @@ +// +// Now that we are familiar with the principles of multithreading, we +// boldly venture into a practical example from mathematics. +// We will determine the circle number PI with sufficient accuracy. +// +// There are different methods for this, and some of them are several +// hundred years old. For us, the dusty procedures are surprisingly well +// suited to our exercise. Because the mathematicians of the time didn't +// have fancy computers with which we can calculate something like this +// in seconds today. +// Whereby, of course, it depends on the accuracy, i.e. how many digits +// after the decimal point we are interested in. +// But these old procedures can still be tackled with paper and pencil, +// which is why they are easier for us to understand. +// At least for me. ;-) +// +// So let's take a mental leap back a few years. +// Around 1672 (if you want to know and read about it in detail, you can +// do so on Wikipedia, for example), various mathematicians once again +// discovered a method of approaching the circle number PI. +// There were the Scottish mathematician Gregory and the German +// mathematician Leibniz, and even a few hundred years earlier the Indian +// mathematician Madhava. All of them independently developed the same +// formula, which was published by Leibnitz in 1682 in the journal +// "Acta Eruditorum". +// This is why this method has become known as the "Leibnitz series", +// although the other names are also often used today. +// We will not go into the formula and its derivation in detail, but +// will deal with the series straight away: +// +// 4 4 4 4 4 +// PI = --- - --- + --- - --- + --- ... +// 1 3 5 7 9 +// +// As you can clearly see, the series starts with the whole number 4 and +// approaches the circle number by subtracting and adding smaller and +// smaller parts of 4. Pretty much everyone has learned PI = 3.14 at school, +// but very few people remember other digits, and this is rarely necessary +// in practice. Because either you don't need the precision, or you use a +// calculator in which the number is stored as a very precise constant. +// But at some point this constant was calculated and we are doing the same +// now.The question at this point is, how many partial values do we have +// to calculate for which accuracy? +// +// The answer is chewing, to get 8 digits after the decimal point we need +// 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 diggits. But the 8 digits are +// enough for us for now, because we want to understand the principle and +// nothing more, right? +// +// As we have already discovered, the Leibnitz series is a series with a +// fixed distance of 2 between the individual partial values. This makes +// it easy to apply a simple loop to it, because if we start with n = 1 +// (which is not necessarily useful now) we always have to add 2 in each +// round. +// But wait! The partial values are alternately added and subtracted. +// This could also be achieved with one loop, but not very elegantly. +// It also makes sense to split this between two CPUs, one calculates +// the positive values and the other the negative values. And so we can +// simply start two threads and add everything up at the end and we're +// done. +// We just have to remember that if only the positive or negative values +// are calculated, the distances are twice as large, i.e. 4. +// +// So that the whole thing has a real learning effect, the first thread +// call is specified and you have to make the second. +// But don't worry, it will work out. :-) +// +const std = @import("std"); + +pub fn main() !void { + const count = 1_000_000_000; + var pi_plus: f64 = 0; + var pi_minus: f64 = 0; + + { + // First thread to calculate the plus numbers. + const handle1 = try std.Thread.spawn(.{}, thread_pi, .{ &pi_plus, 5, count }); + defer handle1.join(); + + // Second thread to calculate the minus numbers. + ??? + + } + // Here we add up the results. + std.debug.print("PI ≈ {d:.8}\n", .{4 + pi_plus - pi_minus}); +} + +fn thread_pi(pi: *f64, begin: u64, end: u64) !void { + var n: u64 = begin; + while (n < end) : (n += 4) { + pi.* += 4 / @as(f64, @floatFromInt(n)); + } +} +// If you wish, you can increase the number of loop passes, which +// improves the number of digits. +// +// But be careful: +// In order for parallel processing to really show its strengths, +// the compiler must be given the "-O ReleaseFast" flag when it +// is created. Otherwise the debug functions slow down the speed +// to such an extent that seconds become minutes during execution. +// +// And you should remove the formatting restriction in "print", +// otherwise you will not be able to see the additional diggits. diff --git a/patches/patches/105_threading2.patch b/patches/patches/105_threading2.patch new file mode 100644 index 0000000..dfa5613 --- /dev/null +++ b/patches/patches/105_threading2.patch @@ -0,0 +1,13 @@ +--- exercises/105_threading2.zig 2024-03-23 16:35:14.754540802 +0100 ++++ answers/105_threading2.zig 2024-03-23 16:38:00.577539733 +0100 +@@ -81,8 +81,8 @@ + defer handle1.join(); + + // Second thread to calculate the minus numbers. +- ??? +- ++ const handle2 = try std.Thread.spawn(.{}, thread_pi, .{ &pi_minus, 3, count }); ++ defer handle2.join(); + } + // Here we add up the results. + std.debug.print("PI ≈ {d:.8}\n", .{4 + pi_plus - pi_minus}); From 95cfeaa6066af582bb4924cb5f4ec89a1b04b539 Mon Sep 17 00:00:00 2001 From: Chris Boesch Date: Sat, 23 Mar 2024 15:57:33 +0000 Subject: [PATCH 10/13] Update exercises/105_threading2.zig Fixed typo. --- exercises/105_threading2.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/105_threading2.zig b/exercises/105_threading2.zig index a211551..1330999 100644 --- a/exercises/105_threading2.zig +++ b/exercises/105_threading2.zig @@ -1,5 +1,5 @@ // -// Now that we are familiar with the principles of multithreading, we +// Now that we are familiar with the principles of multi threading, we // boldly venture into a practical example from mathematics. // We will determine the circle number PI with sufficient accuracy. // From 8e6612a59def8d3ce515c15f98aba8198a9d3b8c Mon Sep 17 00:00:00 2001 From: Chris Boesch Date: Sun, 24 Mar 2024 15:45:53 +0000 Subject: [PATCH 11/13] Update .woodpecker/eowyn.yml fix warning --- .woodpecker/eowyn.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.woodpecker/eowyn.yml b/.woodpecker/eowyn.yml index 7140402..a9e8b6e 100644 --- a/.woodpecker/eowyn.yml +++ b/.woodpecker/eowyn.yml @@ -5,8 +5,5 @@ steps: commands: - sh ./patches/eowyn.sh when: - events: - - push - - pull-requests - - cron - cron: "Daily" + events: ["pull-requests", "push", "cron"] + cron: "Daily" From 0d1c76a4107f07cb9a0988cc28df8667822fdc8d Mon Sep 17 00:00:00 2001 From: Chris Boesch Date: Sun, 24 Mar 2024 15:55:43 +0000 Subject: [PATCH 12/13] Update .woodpecker/eowyn.yml --- .woodpecker/eowyn.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.woodpecker/eowyn.yml b/.woodpecker/eowyn.yml index a9e8b6e..b7bda91 100644 --- a/.woodpecker/eowyn.yml +++ b/.woodpecker/eowyn.yml @@ -5,5 +5,8 @@ steps: commands: - sh ./patches/eowyn.sh when: - events: ["pull-requests", "push", "cron"] + events: + - push + - pull-requests + - cron cron: "Daily" From a3de4e3d0f8a96bcc8f6ddbd849b685f8e882d8e Mon Sep 17 00:00:00 2001 From: Chris Boesch Date: Sun, 24 Mar 2024 15:57:39 +0000 Subject: [PATCH 13/13] Update .woodpecker/eowyn.yml --- .woodpecker/eowyn.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.woodpecker/eowyn.yml b/.woodpecker/eowyn.yml index b7bda91..ba505f7 100644 --- a/.woodpecker/eowyn.yml +++ b/.woodpecker/eowyn.yml @@ -9,4 +9,4 @@ steps: - push - pull-requests - cron - cron: "Daily" + cron: "Daily"