zig/std/math/log.zig
Marc Tiehuis 4c16f9a3c3 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.
2017-06-16 20:32:31 +12:00

73 lines
2.2 KiB
Zig

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)));
}