FLANG

int-power.h
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/common.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, Rounding rounding = defaultRounding) {
21 ValueWithRealFlags<REAL> result{factor};
22 if (base.IsNotANumber()) {
23 result.value = REAL::NotANumber();
24 result.flags.set(RealFlag::InvalidArgument);
25 } else if (power.IsZero()) {
26 if (base.IsZero() || base.IsInfinite()) {
27 result.flags.set(RealFlag::InvalidArgument);
28 }
29 } else {
30 bool negativePower{power.IsNegative()};
31 INT absPower{power.ABS().value};
32 REAL squares{base};
33 int nbits{INT::bits - absPower.LEADZ()};
34 for (int j{0}; j < nbits; ++j) {
35 if (absPower.BTEST(j)) {
36 if (negativePower) {
37 result.value = result.value.Divide(squares, rounding)
38 .AccumulateFlags(result.flags);
39 } else {
40 result.value = result.value.Multiply(squares, rounding)
41 .AccumulateFlags(result.flags);
42 }
43 }
44 squares =
45 squares.Multiply(squares, rounding).AccumulateFlags(result.flags);
46 }
47 }
48 return result;
49 }
50
51 template <typename REAL, typename INT>
52 ValueWithRealFlags<REAL> IntPower(
53 const REAL &base, const INT &power, Rounding rounding = defaultRounding) {
54 REAL one{REAL::FromInteger(INT{1}).value};
55 return TimesIntPowerOf(one, base, power, rounding);
56 }
57 } // namespace Fortran::evaluate
58 #endif // FORTRAN_EVALUATE_INT_POWER_H_