aboutsummaryrefslogtreecommitdiff
path: root/std/math/log.zig
diff options
context:
space:
mode:
authorMarc Tiehuis <marctiehuis@gmail.com>2017-06-16 20:26:10 +1200
committerMarc Tiehuis <marctiehuis@gmail.com>2017-06-16 20:32:31 +1200
commit4c16f9a3c35b23b9917f2a27b91ba8cd20e6fd82 (patch)
tree778f0f06734f7dc17e9269ee1cf5b513f7b504c0 /std/math/log.zig
parent865b53f2860405a718262abf9a794d2bf9529dbc (diff)
downloadzig-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.zig72
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)));
+}