diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..87ed3eb --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.js +TODO.md + diff --git a/etc/_sidebar.md b/etc/_sidebar.md index 53040be..c879c72 100644 --- a/etc/_sidebar.md +++ b/etc/_sidebar.md @@ -3,8 +3,8 @@ - [Home](/ "LibC to Zig: Home") - Tips and Tricks - - [Handling strings](/tips_tricks/01_handling_strings.md) - - [Allocator](/tips_tricks/01_allocator.md) + - [Handling strings](/tips_tricks/handling_strings.md) + - [Allocator](/tips_tricks/allocator.md) - Headers - [\](/headers/assert_h.md "LibC to Zig: ") diff --git a/headers/assert_h.md b/headers/assert_h.md index 59eb760..4c8c864 100644 --- a/headers/assert_h.md +++ b/headers/assert_h.md @@ -1,8 +1,63 @@ # \ -Reference: [\](https://en.cppreference.com/w/c/assert) +C Reference: [\](https://en.cppreference.com/w/c/error) -## Types +Relevant Zig Documentation: + - [std.debug.assert](https://ziglang.org/documentation/master/std/#std;debug.assert) -## Functions +## [assert()](https://en.cppreference.com/w/c/error/assert) +For the following C code, which will immediately abort the program if the condition is false. + +```c +double x = -1.0; +assert(x >= 0.0); +``` + +**Equivalent Zig implementation:** + +```zig +const assert = std.debug.assert; +// ... +const x: double = -1.0; +assert(x >= 0.0); // undefined behaviour +``` + +This will invoke an undefined behaviour when the condition is `false`. Checkout [std.debug.assert](https://ziglang.org/documentation/master/std/#std;debug.assert) +for more information. + +#### Testing with Assert + +In Zig, it is recommended to use functions provided by [std.testing](https://ziglang.org/documentation/master/std/#std;testing) +when you are trying to do assertion inside `tests`. + +For the above example, use: + +```zig +const testing = std.testing; + +test "testing double size" { + const x: double = -1.0; + testing.expect(x >= 0.0); // test fails! +} +``` + +Here, a message is printed to `stderr` and then `abort` is called. Another alternative would be: + +```zig +const testing = std.testing; + +test "testing equivalence" { + const x1: double = -1.970; + const x2: double = -1.970; + std.testing.expectApproxEqAbs(x1, x2, 0.0000001); // floating point number comparison with tolerance + + const x3: int = 1; + const x4: int = 2; + std.testing.expectEq(x3, x3); // failed tests +} +``` + +## [static_assert](https://en.cppreference.com/w/c/error/static_assert) + +Zig handles compile time diagnostic without any extra shenanigans. So, use the above functions in a similar fashion. diff --git a/headers/complex_h.md b/headers/complex_h.md index 00bd1e9..8badeea 100644 --- a/headers/complex_h.md +++ b/headers/complex_h.md @@ -1,8 +1,229 @@ # \ -Reference: [\](https://en.cppreference.com/w/c/complex) +C Reference: [\][0] -## Types +Relevant Zig documentation: +- [std.math.complex][20] -## Functions +## [C imaginary Type][1] +This type allows you to write imaginary constants in C: + +```c +double imaginary i = 2.0 * I; // pure imaginary +double complex z = 1.0 + i; // complex number +``` + +In Zig, there are no imaginary types and you will be representing +the same using [Complex](#zig-complex-type) struct: + +```zig +const complex = @import("std").math.complex; + +const imaginary i = 2.0; +const z = complex.Complex { re: 1.0, im: i }; +``` + +!> Note that imaginary types in C don't have Zig equivalent, you have to denote them as +a [Complex](#zig-complex-type) type. + + +## [Zig Complex Type][21] + +In Zig complex numbers are represented as `Complex` type. +It takes in two variables, `re` and `im` which represent real and imaginary +numbers respectively. + +```zig +const std = @import("std"); +const complex = std.math.complex; + +const Complex = complex.Complex; + +const z1 = Complex { re: 0, im: 1.0 } ; +const z2 = Complex { re: 0, im: 2.0 }; + +test "complex multiplication" { + const zSquared: Complex = complex.mul(z1, z2); + std.debug.print("{d} + i{d}\n", zSquared.re, zSquared.im); +} +``` +--- + +## Functions - Manipulation + +Here are a few functions in __C__ for handling complex types with their __Zig__ equivalent. + +### [CMPLX, CMPLXF, CMPLXL][2] + +They help create the `float complex` type in C. `CMPLXF` and `CMPLXL` are used to create +similar types but for `double` and `long double` respectively. + +```c +double complex z = CMPLX(0.0, -0.0); +printf("z = %.1f%+.1fi\n", creal(z), cimag(z)); +``` +The equivalent Zig code is quite simple: + +```zig +const std = @import("std"); +const complex = std.math.complex + +const z = complex.Complex { re: 0, im: -0.0 }; +std.debug.print("{lf}{lf}\n", z.re, z.im); +``` + +### [crealf, creal, creall][3] + +Returns the real part of a complex number in C. + +```c +double complex z = CMPLX(1.0, 2.0); +printf("%f%+fi\n", creal(z), cimag(z)); +``` + +In Zig its just a struct access: + +```zig +const z = std.complex.Complex { re: 0, im: -0.0 }; +std.debug.print("{lf}+{lf}i\n", z.re, z.im); +``` + +### [cimag, cimagf, cimagl][4] + +Returns the imaginary part of a complex number in C. + +```c +double complex z = CMPLX(1.0, 2.0); +printf("%f%+fi\n", creal(z), cimag(z)); +``` + +In Zig its just a struct access: + +```zig +const complex = @import("std").math.complex; + +const z = std.math.complex.Complex { re: 0, im: -0.0 }; +std.debug.print("{lf}+{lf}i\n", z.re, z.im); +``` + +### [cabs, cabsf, cabsl][5] + +Computes the complex absolute value (Known as norm: `|z|`) of a complex number + +```c +double complex z = 1.0 + 1.0 * I; +printf("|%.1f%+.1fi| = %f\n", creal(z), cimag(z), cabs(z)); +``` + +For Zig, [std.math.complex.abs][24] is used and the equivalent code will be: + +```zig +const std = @import("std"); +const complex = std.math.complex; + +const z = complex.Complex { re: 1.0, im: -1.0 }; +std.debug.print("|{lf}+{lf}i| = {lf}\n", z.re, z.im, complex.abs(z)); +``` + +### [cargf, carg, cargl][6] + +Computes the argument (also called phase angle) of `z`, with a branch cut along +the negative real axis. Here's an example: + +```c +double complex z1 = 1.0 + 0.0 * I; +printf("phase angle of %.lf%+.lfi is %f\n", creal(z1), cimag(z1), carg(z1)); + +double complex z2 = -1.0 + 0.0 * I; +printf("phase angle of %.lf%+.lfi is %f\n", creal(z1), cimag(z1), carg(z1)); +``` + +In Zig we use [std.math.complex.arg][25] for the same. The equivalent code for the above +will be: + +```zig +const std = @import("std"); +const complex = std.math.complex; +const Complex = complex.Complex; + +const z1 = Complex { re: 1.0, im: 0.0 } ; +std.debug.print("phase angle of {lf}+{lf} is {lf}\n", z1.re, z1.im, complex.arg(z1)); +const z2 = Complex { re: -1.0, im: 0.0 } ; +std.debug.print("phase angle of {lf}+{lf} is {lf}\n", z2.re, z2.im, complex.arg(z2)); +``` + +### [conjf, conj, conjl][7] + +Computes the [complex conjugate][40] of a complex number _z_ by reversing the sign of the imaginary part. +Here's a C example: + +```c +double complex z = 1.0 + 2.0*I; +double complex z2 = conj(z); + +printf("The conjugate of %.1f%+.1fi is %.1f%+.1fi\n", + creal(z), cimag(z), creal(z2), cimag(z2)); + +printf("Their product is %.1f%+.1fi\n", creal(z*z2), cimag(z*z2)); +``` + +In Zig, we use [std.math.complex.Complex.conjugate][23] method for the same: + +```zig +const std = @import("std"); +const complex = std.math.complex; +const Complex = complex.Complex; + +const z1 = Complex { re: 1.0, im: 0.0 }; + +const z2 = z1.conjugate(); + +std.debug.print("The conjugate of {lf}+{lf}i is {lf}+{lf}i\n", + z1.re, z1.im, z2.re, z2.im); + +std.debug.print("Their product is {lf}+{lf}i\n", z1.mul(z2).re, z1.mul(z2).im); +``` + +### [cexp][4] + +It computes the complex base-e exponential of `z`. Looking at an example in C: + +```c +double PI = acos(-1); +double complex z = cexp(I * PI); // Euler's formula +printf("exp(i * pi) = %.lf% + .1fi\n", creal(z), cimag(z)); +``` + +In Zig you use [std.math.complex.exp][22] to represent the same. + +```zig +const math = @import("std").math. +const complex = math.complex; + +const PI = math.acos(- 1); + +const z = complex.mul(complex.Complex { re: I, im: }, PI); +``` + +!> [cexpf][3] & [cexpl][3] are two variants in C that take `float` and `long double` respectively in C. In Zig those variants +are handled quite well by Zig generics. + + +[0]: https://en.cppreference.com/w/c/numeric/complex "C -Complex" +[1]: https://en.cppreference.com/w/c/numeric/complex/imaginary "C -Imaginary" +[2]: https://en.cppreference.com/w/c/numeric/complex/CMPLX +[3]: https://en.cppreference.com/w/c/numeric/complex/creal +[4]: https://en.cppreference.com/w/c/numeric/complex/cimag +[5]: https://en.cppreference.com/w/c/numeric/complex/cabs +[6]: https://en.cppreference.com/w/c/numeric/complex/carg +[7]: https://en.cppreference.com/w/c/numeric/complex/conj + + +[20]: https://ziglang.org/documentation/master/std/#std;math.complex +[21]: https://ziglang.org/documentation/master/std/#std;math.complex.Complex +[22]: https://ziglang.org/documentation/master/std/#std;math.complex.exp +[23]: https://ziglang.org/documentation/master/std/#std;math.complex.Complex.conjugate + + +[40]: https://en.wikipedia.org/wiki/Complex_conjugate diff --git a/index.html b/index.html index 3d6d08b..80af80b 100644 --- a/index.html +++ b/index.html @@ -1,7 +1,7 @@ - + Document @@ -47,6 +47,15 @@ .markdown-section { max-width: 90%; } + .markdown-section p.tip { + border-left: 4px solid #f7a31d; + } + .markdown-section p.tip::before { + background-color: #f7a31d; + } + .markdown-section pre > code { + color: #c5cbce; + } @@ -55,8 +64,8 @@ window.$docsify = { name: "LibC to Zig ⚡", repo: "https://github.com/zig-community/libc-to-zig", - loadSidebar: 'etc/_sidebar.md', - subMaxLevel: 2, + loadSidebar: "etc/_sidebar.md", + subMaxLevel: 3, search: "auto", themeColor: "#f7a31d", homepage: "index.md", diff --git a/index.md b/index.md index 3cb0df0..5b77989 100644 --- a/index.md +++ b/index.md @@ -17,37 +17,37 @@ Comparison between libc functions and their best fitting zig alternatives - [Home](/) -| Headers | Tips Tricks | +| Tips & Tricks | Headers | | --- | --- | -| [\](/headers/assert_h.md "LibC to Zig: ") | [Handling strings](/tips_tricks/01_handling_strings.md) | -| [\](/headers/complex_h.md "LibC to Zig: ") | [Allocator](/tips_tricks/01_allocator.md) | -| [\](/headers/ctype_h.md "LibC to Zig: ") | | -| [\](/headers/errno_h.md "LibC to Zig: ") | | -| [\](/headers/fenv_h.md "LibC to Zig: ") | | -| [\](/headers/float_h.md "LibC to Zig: ") | | -| [\](/headers/inttypes_h.md "LibC to Zig: ") | | -| [\](/headers/iso646_h.md "LibC to Zig: ") | | -| [\](/headers/limits_h.md "LibC to Zig: ") | | -| [\](/headers/locale_h.md "LibC to Zig: ") | | -| [\](/headers/math_h.md "LibC to Zig: ") | | -| [\](/headers/setjmp_h.md "LibC to Zig: ") | | -| [\](/headers/signal_h.md "LibC to Zig: ") | | -| [\](/headers/stdalign_h.md "LibC to Zig: ") | | -| [\](/headers/stdarg_h.md "LibC to Zig: ") | | -| [\](/headers/stdatomic_h.md "LibC to Zig: ") | | -| [\](/headers/stdbool_h.md "LibC to Zig: ") | | -| [\](/headers/stddef_h.md "LibC to Zig: ") | | -| [\](/headers/stdint_h.md "LibC to Zig: ") | | -| [\](/headers/stdio_h.md "LibC to Zig: ") | | -| [\](/headers/stdlib_h.md "LibC to Zig: ") | | -| [\](/headers/stdnoreturn_h.md "LibC to Zig: ") | | -| [\](/headers/string_h.md "LibC to Zig: ") | | -| [\](/headers/tgmath_h.md "LibC to Zig: ") | | -| [\](/headers/threads_h.md "LibC to Zig: ") | | -| [\](/headers/time_h.md "LibC to Zig: ") | | -| [\](/headers/uchar_h.md "LibC to Zig: ") | | -| [\](/headers/wchar_h.md "LibC to Zig: ") | | -| [\](/headers/wctype_h.md "LibC to Zig: ") | | +| [Handling strings](/tips_tricks/handling_strings.md) | [\](/headers/assert_h.md "LibC to Zig: ") | +| [Allocator](/tips_tricks/allocator.md) | [\](/headers/complex_h.md "LibC to Zig: ") | +| [Pointers](/tips_tricks/pointers.md) | [\](/headers/ctype_h.md "LibC to Zig: ") | +| | [\](/headers/errno_h.md "LibC to Zig: ") | +| | [\](/headers/fenv_h.md "LibC to Zig: ") | +| | [\](/headers/float_h.md "LibC to Zig: ") | +| | [\](/headers/inttypes_h.md "LibC to Zig: ") | +| | [\](/headers/iso646_h.md "LibC to Zig: ") | +| | [\](/headers/limits_h.md "LibC to Zig: ") | +| | [\](/headers/locale_h.md "LibC to Zig: ") | +| | [\](/headers/math_h.md "LibC to Zig: ") | +| | [\](/headers/setjmp_h.md "LibC to Zig: ") | +| | [\](/headers/signal_h.md "LibC to Zig: ") | +| | [\](/headers/stdalign_h.md "LibC to Zig: ") | +| | [\](/headers/stdarg_h.md "LibC to Zig: ") | +| | [\](/headers/stdatomic_h.md "LibC to Zig: ") | +| | [\](/headers/stdbool_h.md "LibC to Zig: ") | +| | [\](/headers/stddef_h.md "LibC to Zig: ") | +| | [\](/headers/stdint_h.md "LibC to Zig: ") | +| | [\](/headers/stdio_h.md "LibC to Zig: ") | +| | [\](/headers/stdlib_h.md "LibC to Zig: ") | +| | [\](/headers/stdnoreturn_h.md "LibC to Zig: ") | +| | [\](/headers/string_h.md "LibC to Zig: ") | +| | [\](/headers/tgmath_h.md "LibC to Zig: ") | +| | [\](/headers/threads_h.md "LibC to Zig: ") | +| | [\](/headers/time_h.md "LibC to Zig: ") | +| | [\](/headers/uchar_h.md "LibC to Zig: ") | +| | [\](/headers/wchar_h.md "LibC to Zig: ") | +| | [\](/headers/wctype_h.md "LibC to Zig: ") | ## Contributing diff --git a/tips_tricks/01_allocator.md b/tips_tricks/allocator.md similarity index 100% rename from tips_tricks/01_allocator.md rename to tips_tricks/allocator.md diff --git a/tips_tricks/01_handling_strings.md b/tips_tricks/handling_strings.md similarity index 100% rename from tips_tricks/01_handling_strings.md rename to tips_tricks/handling_strings.md diff --git a/tips_tricks/pointers.md b/tips_tricks/pointers.md new file mode 100644 index 0000000..eee6218 --- /dev/null +++ b/tips_tricks/pointers.md @@ -0,0 +1,7 @@ +# Pointers + +Guide to using pointers in Zig from a C perspective + +## Relevant Zig doc + +- [ ] [std](https://ziglang.org/documentation/master/std/#std;)