authorgravatar for emekankurumeh@outlook.comemekoi <emekankurumeh@outlook.com> 2018-10-10 09:50:23-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-10-10 10:50:23-04:00
loga22d9daaecd94f71690e6296aff3ee0a2da00892
treebaaa174b683958eda2384907fdd8aaef5e1aa102
parent9e38a81230bcaefb50fae610c071005449a7abfb

added math.pow support for integer types. resolves #1637 (#1642)

added math.powi for integers; pow now handles ints

4 files changed, 182 insertions(+), 0 deletions(-)

CMakeLists.txt+1
...@@ -554,6 +554,7 @@ set(ZIG_STD_FILES...@@ -554,6 +554,7 @@ set(ZIG_STD_FILES
554 "math/modf.zig"554 "math/modf.zig"
555 "math/nan.zig"555 "math/nan.zig"
556 "math/pow.zig"556 "math/pow.zig"
557 "math/powi.zig"
557 "math/round.zig"558 "math/round.zig"
558 "math/scalbn.zig"559 "math/scalbn.zig"
559 "math/signbit.zig"560 "math/signbit.zig"
std/math/index.zig+2
...@@ -119,6 +119,7 @@ pub const isNormal = @import("isnormal.zig").isNormal;...@@ -119,6 +119,7 @@ pub const isNormal = @import("isnormal.zig").isNormal;
119pub const signbit = @import("signbit.zig").signbit;119pub const signbit = @import("signbit.zig").signbit;
120pub const scalbn = @import("scalbn.zig").scalbn;120pub const scalbn = @import("scalbn.zig").scalbn;
121pub const pow = @import("pow.zig").pow;121pub const pow = @import("pow.zig").pow;
122pub const powi = @import("powi.zig").powi;
122pub const sqrt = @import("sqrt.zig").sqrt;123pub const sqrt = @import("sqrt.zig").sqrt;
123pub const cbrt = @import("cbrt.zig").cbrt;124pub const cbrt = @import("cbrt.zig").cbrt;
124pub const acos = @import("acos.zig").acos;125pub const acos = @import("acos.zig").acos;
...@@ -168,6 +169,7 @@ test "math" {...@@ -168,6 +169,7 @@ test "math" {
168 _ = @import("signbit.zig");169 _ = @import("signbit.zig");
169 _ = @import("scalbn.zig");170 _ = @import("scalbn.zig");
170 _ = @import("pow.zig");171 _ = @import("pow.zig");
172 _ = @import("powi.zig");
171 _ = @import("sqrt.zig");173 _ = @import("sqrt.zig");
172 _ = @import("cbrt.zig");174 _ = @import("cbrt.zig");
173 _ = @import("acos.zig");175 _ = @import("acos.zig");
std/math/pow.zig+4
...@@ -28,6 +28,10 @@ const assert = std.debug.assert;...@@ -28,6 +28,10 @@ const assert = std.debug.assert;
2828
29// This implementation is taken from the go stlib, musl is a bit more complex.29// This implementation is taken from the go stlib, musl is a bit more complex.
30pub fn pow(comptime T: type, x: T, y: T) T {30pub fn pow(comptime T: type, x: T, y: T) T {
31 if (@typeInfo(T) == builtin.TypeId.Int) {
32 return math.powi(T, x, y) catch unreachable;
33 }
34
31 if (T != f32 and T != f64) {35 if (T != f32 and T != f64) {
32 @compileError("pow not implemented for " ++ @typeName(T));36 @compileError("pow not implemented for " ++ @typeName(T));
33 }37 }
std/math/powi.zig created+175
...@@ -0,0 +1,175 @@
1// Special Cases:
2//
3// powi(x, +-0) = 1 for any x
4// powi(0, y) = 1 for any y
5// powi(1, y) = 1 for any y
6// powi(-1, y) = -1 for for y an odd integer
7// powi(-1, y) = 1 for for y an even integer
8// powi(x, y) = Overflow for for y >= @sizeOf(x) - 1 y > 0
9// powi(x, y) = Underflow for for y > @sizeOf(x) - 1 y < 0
10
11const builtin = @import("builtin");
12const std = @import("../index.zig");
13const math = std.math;
14const assert = std.debug.assert;
15const assertError = std.debug.assertError;
16
17// This implementation is based on that from the rust stlib
18pub fn powi(comptime T: type, x: T, y: T) (error{Overflow, Underflow}!T) {
19 const info = @typeInfo(T);
20
21 comptime assert(@typeInfo(T) == builtin.TypeId.Int);
22
23 // powi(x, +-0) = 1 for any x
24 if (y == 0 or y == -0) {
25 return 0;
26 }
27
28 switch (x) {
29 // powi(0, y) = 1 for any y
30 0 => return 0,
31
32 // powi(1, y) = 1 for any y
33 1 => return 1,
34
35 else => {
36 // powi(x, y) = Overflow for for y >= @sizeOf(x) - 1 y > 0
37 // powi(x, y) = Underflow for for y > @sizeOf(x) - 1 y < 0
38 const bit_size = @sizeOf(T) * 8;
39 if (info.Int.is_signed) {
40
41 if (x == -1) {
42 // powi(-1, y) = -1 for for y an odd integer
43 // powi(-1, y) = 1 for for y an even integer
44 if (@mod(y, 2) == 0) {
45 return 1;
46 } else {
47 return -1;
48 }
49 }
50
51 if (x > 0 and y >= bit_size - 1) {
52 return error.Overflow;
53 } else if (x < 0 and y > bit_size - 1) {
54 return error.Underflow;
55 }
56 } else {
57 if (y >= bit_size) {
58 return error.Overflow;
59 }
60 }
61
62 var base = x;
63 var exp = y;
64 var acc: T = 1;
65
66 while (exp > 1) {
67 if (exp & 1 == 1) {
68 if (@mulWithOverflow(T, acc, base, &acc)) {
69 if (x > 0) {
70 return error.Overflow;
71 } else {
72 return error.Underflow;
73 }
74 }
75 }
76
77 exp >>= 1;
78
79 if (@mulWithOverflow(T, base, base, &base)) {
80 if (x > 0) {
81 return error.Overflow;
82 } else {
83 return error.Underflow;
84 }
85 }
86 }
87
88 if (exp == 1) {
89 if (@mulWithOverflow(T, acc, base, &acc)) {
90 if (x > 0) {
91 return error.Overflow;
92 } else {
93 return error.Underflow;
94 }
95 }
96 }
97
98 return acc;
99 }
100 }
101}
102
103test "math.powi" {
104 assertError(powi(i8, -66, 6), error.Underflow);
105 assertError(powi(i16, -13, 13), error.Underflow);
106 assertError(powi(i32, -32, 21), error.Underflow);
107 assertError(powi(i64, -24, 61), error.Underflow);
108 assertError(powi(i17, -15, 15), error.Underflow);
109 assertError(powi(i42, -6, 40), error.Underflow);
110
111 assert((try powi(i8, -5, 3)) == -125);
112 assert((try powi(i16, -16, 3)) == -4096);
113 assert((try powi(i32, -91, 3)) == -753571);
114 assert((try powi(i64, -36, 6)) == 2176782336);
115 assert((try powi(i17, -2, 15)) == -32768);
116 assert((try powi(i42, -5, 7)) == -78125);
117
118 assert((try powi(u8, 6, 2)) == 36);
119 assert((try powi(u16, 5, 4)) == 625);
120 assert((try powi(u32, 12, 6)) == 2985984);
121 assert((try powi(u64, 34, 2)) == 1156);
122 assert((try powi(u17, 16, 3)) == 4096);
123 assert((try powi(u42, 34, 6)) == 1544804416);
124
125 assertError(powi(i8, 120, 7), error.Overflow);
126 assertError(powi(i16, 73, 15), error.Overflow);
127 assertError(powi(i32, 23, 31), error.Overflow);
128 assertError(powi(i64, 68, 61), error.Overflow);
129 assertError(powi(i17, 15, 15), error.Overflow);
130 assertError(powi(i42, 121312, 41), error.Overflow);
131
132 assertError(powi(u8, 123, 7), error.Overflow);
133 assertError(powi(u16, 2313, 15), error.Overflow);
134 assertError(powi(u32, 8968, 31), error.Overflow);
135 assertError(powi(u64, 2342, 63), error.Overflow);
136 assertError(powi(u17, 2723, 16), error.Overflow);
137 assertError(powi(u42, 8234, 41), error.Overflow);
138}
139
140test "math.powi.special" {
141 assertError(powi(i8, -2, 8), error.Underflow);
142 assertError(powi(i16, -2, 16), error.Underflow);
143 assertError(powi(i32, -2, 32), error.Underflow);
144 assertError(powi(i64, -2, 64), error.Underflow);
145 assertError(powi(i17, -2, 17), error.Underflow);
146 assertError(powi(i42, -2, 42), error.Underflow);
147
148 assert((try powi(i8, -1, 3)) == -1);
149 assert((try powi(i16, -1, 2)) == 1);
150 assert((try powi(i32, -1, 16)) == 1);
151 assert((try powi(i64, -1, 6)) == 1);
152 assert((try powi(i17, -1, 15)) == -1);
153 assert((try powi(i42, -1, 7)) == -1);
154
155 assert((try powi(u8, 1, 2)) == 1);
156 assert((try powi(u16, 1, 4)) == 1);
157 assert((try powi(u32, 1, 6)) == 1);
158 assert((try powi(u64, 1, 2)) == 1);
159 assert((try powi(u17, 1, 3)) == 1);
160 assert((try powi(u42, 1, 6)) == 1);
161
162 assertError(powi(i8, 2, 7), error.Overflow);
163 assertError(powi(i16, 2, 15), error.Overflow);
164 assertError(powi(i32, 2, 31), error.Overflow);
165 assertError(powi(i64, 2, 63), error.Overflow);
166 assertError(powi(i17, 2, 16), error.Overflow);
167 assertError(powi(i42, 2, 41), error.Overflow);
168
169 assertError(powi(u8, 2, 8), error.Overflow);
170 assertError(powi(u16, 2, 16), error.Overflow);
171 assertError(powi(u32, 2, 32), error.Overflow);
172 assertError(powi(u64, 2, 64), error.Overflow);
173 assertError(powi(u17, 2, 17), error.Overflow);
174 assertError(powi(u42, 2, 42), error.Overflow);
175}