diff options
| author | Marc Tiehuis <marctiehuis@gmail.com> | 2017-06-16 20:26:10 +1200 |
|---|---|---|
| committer | Marc Tiehuis <marctiehuis@gmail.com> | 2017-06-16 20:32:31 +1200 |
| commit | 4c16f9a3c35b23b9917f2a27b91ba8cd20e6fd82 (patch) | |
| tree | 778f0f06734f7dc17e9269ee1cf5b513f7b504c0 /std/math/log.zig | |
| parent | 865b53f2860405a718262abf9a794d2bf9529dbc (diff) | |
| download | zig-4c16f9a3c35b23b9917f2a27b91ba8cd20e6fd82.tar.gz zig-4c16f9a3c35b23b9917f2a27b91ba8cd20e6fd82.zip | |
Add math library
This covers the majority of the functions as covered by the C99
specification for a math library.
Code is adapted primarily from musl libc, with the pow and standard
trigonometric functions adapted from the Go stdlib.
Changes:
- Remove assert expose in index and import as needed.
- Add float log function and merge with existing base 2 integer
implementation.
See https://github.com/tiehuis/zig-fmath.
See #374.
Diffstat (limited to 'std/math/log.zig')
| -rw-r--r-- | std/math/log.zig | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/std/math/log.zig b/std/math/log.zig new file mode 100644 index 0000000000..abd480b6a6 --- /dev/null +++ b/std/math/log.zig @@ -0,0 +1,72 @@ +const math = @import("index.zig"); +const builtin = @import("builtin"); +const assert = @import("../debug.zig").assert; + +pub fn log(comptime base: usize, x: var) -> @typeOf(x) { + const T = @typeOf(x); + switch (@typeId(T)) { + builtin.TypeId.Int => { + if (base == 2) { + return T.bit_count - 1 - @clz(x); + } else { + @compileError("TODO implement log for non base 2 integers"); + } + }, + + builtin.TypeId.Float => { + return logf(base, x); + }, + + else => { + @compileError("log expects integer or float, found '" ++ @typeName(T) ++ "'"); + }, + } +} + +fn logf(comptime base: usize, x: var) -> @typeOf(x) { + const T = @typeOf(x); + switch (T) { + f32 => { + switch (base) { + 2 => return math.log2(x), + 10 => return math.log10(x), + else => return f32(math.ln(f64(x)) / math.ln(f64(base))), + } + }, + + f64 => { + switch (base) { + 2 => return math.log2(x), + 10 => return math.log10(x), + // NOTE: This likely is computed with reduced accuracy. + else => return math.ln(x) / math.ln(f64(base)), + } + }, + + else => @compileError("log not implemented for " ++ @typeName(T)), + } +} + +test "log_integer" { + assert(log(2, u8(0x1)) == 0); + assert(log(2, u8(0x2)) == 1); + assert(log(2, i16(0x72)) == 6); + assert(log(2, u32(0xFFFFFF)) == 23); + assert(log(2, u64(0x7FF0123456789ABC)) == 62); +} + +test "log_float" { + const epsilon = 0.000001; + + assert(math.approxEq(f32, log(6, f32(0.23947)), -0.797723, epsilon)); + assert(math.approxEq(f32, log(89, f32(0.23947)), -0.318432, epsilon)); + assert(math.approxEq(f64, log(123897, f64(12389216414)), 1.981724596, epsilon)); +} + +test "log_float_special" { + assert(log(2, f32(0.2301974)) == math.log2(f32(0.2301974))); + assert(log(10, f32(0.2301974)) == math.log10(f32(0.2301974))); + + assert(log(2, f64(213.23019799993)) == math.log2(f64(213.23019799993))); + assert(log(10, f64(213.23019799993)) == math.log10(f64(213.23019799993))); +} |
