1 | //===-- lib/Evaluate/int-power.h --------------------------------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #ifndef FORTRAN_EVALUATE_INT_POWER_H_ |
10 | #define FORTRAN_EVALUATE_INT_POWER_H_ |
11 | |
12 | // Computes an integer power of a real or complex value. |
13 | |
14 | #include "flang/Evaluate/target.h" |
15 | |
16 | namespace Fortran::evaluate { |
17 | |
18 | template <typename REAL, typename INT> |
19 | ValueWithRealFlags<REAL> TimesIntPowerOf(const REAL &factor, const REAL &base, |
20 | const INT &power, |
21 | Rounding rounding = TargetCharacteristics::defaultRounding) { |
22 | ValueWithRealFlags<REAL> result{factor}; |
23 | if (base.IsNotANumber()) { |
24 | result.value = REAL::NotANumber(); |
25 | result.flags.set(RealFlag::InvalidArgument); |
26 | } else if (power.IsZero()) { |
27 | if (base.IsZero() || base.IsInfinite()) { |
28 | result.flags.set(RealFlag::InvalidArgument); |
29 | } |
30 | } else { |
31 | bool negativePower{power.IsNegative()}; |
32 | INT absPower{power.ABS().value}; |
33 | REAL squares{base}; |
34 | int nbits{INT::bits - absPower.LEADZ()}; |
35 | for (int j{0}; j < nbits; ++j) { |
36 | if (j > 0) { // avoid spurious overflow on last iteration |
37 | squares = |
38 | squares.Multiply(squares, rounding).AccumulateFlags(result.flags); |
39 | } |
40 | if (absPower.BTEST(j)) { |
41 | if (negativePower) { |
42 | result.value = result.value.Divide(squares, rounding) |
43 | .AccumulateFlags(result.flags); |
44 | } else { |
45 | result.value = result.value.Multiply(squares, rounding) |
46 | .AccumulateFlags(result.flags); |
47 | } |
48 | } |
49 | } |
50 | } |
51 | return result; |
52 | } |
53 | |
54 | template <typename REAL, typename INT> |
55 | ValueWithRealFlags<REAL> IntPower(const REAL &base, const INT &power, |
56 | Rounding rounding = TargetCharacteristics::defaultRounding) { |
57 | REAL one{REAL::FromInteger(INT{1}).value}; |
58 | return TimesIntPowerOf(one, base, power, rounding); |
59 | } |
60 | } // namespace Fortran::evaluate |
61 | #endif // FORTRAN_EVALUATE_INT_POWER_H_ |
62 | |