| 1 | //! a raised to integer power of b |
| 2 | //! ported from https://github.com/llvm-mirror/compiler-rt/blob/release_80/lib/builtins/powisf2.c |
| 3 | //! Multiplication order (left-to-right or right-to-left) does not matter for |
| 4 | //! error propagation and this method is optimized for performance, not accuracy. |
| 5 | |
| 6 | const compiler_rt = @import("../compiler_rt.zig"); |
| 7 | const symbol = compiler_rt.symbol; |
| 8 | |
| 9 | comptime { |
| 10 | symbol(&__powihf2, "__powihf2"); |
| 11 | symbol(&__powisf2, "__powisf2"); |
| 12 | symbol(&__powidf2, "__powidf2"); |
| 13 | symbol(&__powixf2, "__powixf2"); |
| 14 | if (compiler_rt.want_ppc_abi) { |
| 15 | symbol(&__powitf2, "__powikf2"); |
| 16 | } else { |
| 17 | symbol(&__powitf2, "__powitf2"); |
| 18 | } |
| 19 | } |
| 20 | |
| 21 | inline fn powiXf2(comptime FT: type, a: FT, b: i32) FT { |
| 22 | var x_a: FT = a; |
| 23 | var x_b: i32 = b; |
| 24 | const is_recip: bool = b < 0; |
| 25 | var r: FT = 1.0; |
| 26 | while (true) { |
| 27 | if (@as(u32, @bitCast(x_b)) & @as(u32, 1) != 0) { |
| 28 | r *= x_a; |
| 29 | } |
| 30 | x_b = @divTrunc(x_b, @as(i32, 2)); |
| 31 | if (x_b == 0) break; |
| 32 | x_a *= x_a; // Multiplication of x_a propagates the error |
| 33 | } |
| 34 | return if (is_recip) 1 / r else r; |
| 35 | } |
| 36 | |
| 37 | fn __powihf2(a: compiler_rt.f16.Abi, b: i32) callconv(.c) compiler_rt.f16.Abi { |
| 38 | return compiler_rt.f16.toAbi(powi_f16(compiler_rt.f16.fromAbi(a), b)); |
| 39 | } |
| 40 | pub fn powi_f16(a: f16, b: i32) f16 { |
| 41 | return powiXf2(f16, a, b); |
| 42 | } |
| 43 | |
| 44 | fn __powisf2(a: compiler_rt.f32.Abi, b: i32) callconv(.c) compiler_rt.f32.Abi { |
| 45 | return compiler_rt.f32.toAbi(powi_f32(compiler_rt.f32.fromAbi(a), b)); |
| 46 | } |
| 47 | pub fn powi_f32(a: f32, b: i32) f32 { |
| 48 | return powiXf2(f32, a, b); |
| 49 | } |
| 50 | |
| 51 | fn __powidf2(a: compiler_rt.f64.Abi, b: i32) callconv(.c) compiler_rt.f64.Abi { |
| 52 | return compiler_rt.f64.toAbi(powi_f64(compiler_rt.f64.fromAbi(a), b)); |
| 53 | } |
| 54 | pub fn powi_f64(a: f64, b: i32) f64 { |
| 55 | return powiXf2(f64, a, b); |
| 56 | } |
| 57 | |
| 58 | fn __powixf2(a: compiler_rt.f80.Abi, b: i32) callconv(.c) compiler_rt.f80.Abi { |
| 59 | return compiler_rt.f80.toAbi(powi_f80(compiler_rt.f80.fromAbi(a), b)); |
| 60 | } |
| 61 | pub fn powi_f80(a: f80, b: i32) f80 { |
| 62 | return powiXf2(f80, a, b); |
| 63 | } |
| 64 | |
| 65 | fn __powitf2(a: compiler_rt.f128.Abi, b: i32) callconv(.c) compiler_rt.f128.Abi { |
| 66 | return compiler_rt.f128.toAbi(powi_f128(compiler_rt.f128.fromAbi(a), b)); |
| 67 | } |
| 68 | pub fn powi_f128(a: f128, b: i32) f128 { |
| 69 | return powiXf2(f128, a, b); |
| 70 | } |
| 71 | |
| 72 | test { |
| 73 | _ = @import("powiXf2_test.zig"); |
| 74 | } |