aboutsummaryrefslogtreecommitdiff
path: root/std/math/log.zig
diff options
context:
space:
mode:
authorAndrew Kelley <superjoe30@gmail.com>2017-08-19 01:32:15 -0400
committerAndrew Kelley <superjoe30@gmail.com>2017-08-19 01:43:43 -0400
commit987768778a67538299f84a6ab7ff0ca65f69d2ac (patch)
tree2e7551d76bf9a3e6d242a961eacf7c81aab6025f /std/math/log.zig
parent558ece8f6f1889bc4773432c16cdf96a54ec1431 (diff)
downloadzig-987768778a67538299f84a6ab7ff0ca65f69d2ac.tar.gz
zig-987768778a67538299f84a6ab7ff0ca65f69d2ac.zip
bit shifting safety
* add u3, u4, u5, u6, u7 and i3, i4, i5, i6, i7 * shift operations shift amount parameter type is integer with log2 bit width of other param - This enforces not violating undefined behavior on shift amount >= bit width with the type system * clean up math.log, math.ln, math.log2, math.log10 closes #403
Diffstat (limited to 'std/math/log.zig')
-rw-r--r--std/math/log.zig70
1 files changed, 36 insertions, 34 deletions
diff --git a/std/math/log.zig b/std/math/log.zig
index 90f28ffc52..180c3aeb31 100644
--- a/std/math/log.zig
+++ b/std/math/log.zig
@@ -1,36 +1,38 @@
const math = @import("index.zig");
const builtin = @import("builtin");
+const TypeId = builtin.TypeId;
const assert = @import("../debug.zig").assert;
// TODO issue #393
pub const log = log_workaround;
-pub fn log_workaround(comptime base: usize, x: var) -> @typeOf(x) {
- const T = @typeOf(x);
+fn log_workaround(comptime T: type, base: T, x: T) -> T {
+ if (base == 2) {
+ return math.log2(x);
+ } else if (base == 10) {
+ return math.log10(x);
+ } else if ((@typeId(T) == TypeId.Float or @typeId(T) == TypeId.FloatLiteral) and base == math.e) {
+ return math.ln(x);
+ }
+
switch (@typeId(T)) {
+ TypeId.FloatLiteral => {
+ return @typeOf(1.0)(math.ln(f64(x)) / math.ln(f64(base)));
+ },
+ TypeId.IntLiteral => {
+ return @typeOf(1)(math.floor(math.ln(f64(x)) / math.ln(f64(base))));
+ },
builtin.TypeId.Int => {
- if (base == 2) {
- return T.bit_count - 1 - @clz(x);
- } else {
- @compileError("TODO implement log for non base 2 integers");
- }
+ // TODO implement integer log without using float math
+ return T(math.floor(math.ln(f64(x)) / math.ln(f64(base))));
},
- builtin.TypeId.Float => 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)),
+ builtin.TypeId.Float => {
+ switch (T) {
+ f32 => return f32(math.ln(f64(x)) / math.ln(f64(base))),
+ f64 => return math.ln(x) / math.ln(f64(base)),
+ else => @compileError("log not implemented for " ++ @typeName(T)),
+ };
},
else => {
@@ -40,25 +42,25 @@ pub fn log_workaround(comptime base: usize, x: var) -> @typeOf(x) {
}
test "math.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);
+ assert(log(u8, 2, 0x1) == 0);
+ assert(log(u8, 2, 0x2) == 1);
+ assert(log(i16, 2, 0x72) == 6);
+ assert(log(u32, 2, 0xFFFFFF) == 23);
+ assert(log(u64, 2, 0x7FF0123456789ABC) == 62);
}
test "math.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));
+ assert(math.approxEq(f32, log(f32, 6, 0.23947), -0.797723, epsilon));
+ assert(math.approxEq(f32, log(f32, 89, 0.23947), -0.318432, epsilon));
+ assert(math.approxEq(f64, log(f64, 123897, 12389216414), 1.981724596, epsilon));
}
test "math.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(f32, 2, 0.2301974) == math.log2(f32(0.2301974)));
+ assert(log(f32, 10, 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)));
+ assert(log(f64, 2, 213.23019799993) == math.log2(f64(213.23019799993)));
+ assert(log(f64, 10, 213.23019799993) == math.log10(f64(213.23019799993)));
}