2017-06-16 01:26:10 -07:00
|
|
|
const math = @import("index.zig");
|
|
|
|
const builtin = @import("builtin");
|
|
|
|
const assert = @import("../debug.zig").assert;
|
|
|
|
|
2017-06-19 11:36:33 -07:00
|
|
|
// TODO issue #393
|
|
|
|
pub const log = log_workaround;
|
|
|
|
|
|
|
|
pub fn log_workaround(comptime base: usize, x: var) -> @typeOf(x) {
|
2017-06-16 01:26:10 -07:00
|
|
|
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");
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2017-06-19 11:36:33 -07:00
|
|
|
builtin.TypeId.Float => switch (T) {
|
|
|
|
f32 => switch (base) {
|
2017-06-16 01:26:10 -07:00
|
|
|
2 => return math.log2(x),
|
|
|
|
10 => return math.log10(x),
|
|
|
|
else => return f32(math.ln(f64(x)) / math.ln(f64(base))),
|
2017-06-19 11:36:33 -07:00
|
|
|
},
|
2017-06-16 01:26:10 -07:00
|
|
|
|
2017-06-19 11:36:33 -07:00
|
|
|
f64 => switch (base) {
|
2017-06-16 01:26:10 -07:00
|
|
|
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)),
|
2017-06-19 11:36:33 -07:00
|
|
|
},
|
|
|
|
|
|
|
|
else => @compileError("log not implemented for " ++ @typeName(T)),
|
2017-06-16 01:26:10 -07:00
|
|
|
},
|
|
|
|
|
2017-06-19 11:36:33 -07:00
|
|
|
else => {
|
|
|
|
@compileError("log expects integer or float, found '" ++ @typeName(T) ++ "'");
|
|
|
|
},
|
2017-06-16 01:26:10 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-19 11:36:33 -07:00
|
|
|
test "math.log integer" {
|
2017-06-16 01:26:10 -07:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2017-06-19 11:36:33 -07:00
|
|
|
test "math.log float" {
|
2017-06-16 01:26:10 -07:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2017-06-19 11:36:33 -07:00
|
|
|
test "math.log float_special" {
|
2017-06-16 01:26:10 -07:00
|
|
|
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)));
|
|
|
|
}
|