xref: /llvm-project/flang/lib/Evaluate/int-power.h (revision 31505c4f6b977c2ccc785de29a047a31563e5c90)
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