• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_
59