xref: /llvm-project/flang/lib/Evaluate/int-power.h (revision 31505c4f6b977c2ccc785de29a047a31563e5c90)
164ab3302SCarolineConcatto //===-- lib/Evaluate/int-power.h --------------------------------*- C++ -*-===//
264ab3302SCarolineConcatto //
364ab3302SCarolineConcatto // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
464ab3302SCarolineConcatto // See https://llvm.org/LICENSE.txt for license information.
564ab3302SCarolineConcatto // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
664ab3302SCarolineConcatto //
764ab3302SCarolineConcatto //===----------------------------------------------------------------------===//
864ab3302SCarolineConcatto 
964ab3302SCarolineConcatto #ifndef FORTRAN_EVALUATE_INT_POWER_H_
1064ab3302SCarolineConcatto #define FORTRAN_EVALUATE_INT_POWER_H_
1164ab3302SCarolineConcatto 
1264ab3302SCarolineConcatto // Computes an integer power of a real or complex value.
1364ab3302SCarolineConcatto 
1423c2bedfSPeter Klausler #include "flang/Evaluate/target.h"
1564ab3302SCarolineConcatto 
1664ab3302SCarolineConcatto namespace Fortran::evaluate {
1764ab3302SCarolineConcatto 
1864ab3302SCarolineConcatto template <typename REAL, typename INT>
1964ab3302SCarolineConcatto ValueWithRealFlags<REAL> TimesIntPowerOf(const REAL &factor, const REAL &base,
2023c2bedfSPeter Klausler     const INT &power,
2123c2bedfSPeter Klausler     Rounding rounding = TargetCharacteristics::defaultRounding) {
2264ab3302SCarolineConcatto   ValueWithRealFlags<REAL> result{factor};
2364ab3302SCarolineConcatto   if (base.IsNotANumber()) {
2464ab3302SCarolineConcatto     result.value = REAL::NotANumber();
2564ab3302SCarolineConcatto     result.flags.set(RealFlag::InvalidArgument);
2664ab3302SCarolineConcatto   } else if (power.IsZero()) {
2764ab3302SCarolineConcatto     if (base.IsZero() || base.IsInfinite()) {
2864ab3302SCarolineConcatto       result.flags.set(RealFlag::InvalidArgument);
2964ab3302SCarolineConcatto     }
3064ab3302SCarolineConcatto   } else {
3164ab3302SCarolineConcatto     bool negativePower{power.IsNegative()};
3264ab3302SCarolineConcatto     INT absPower{power.ABS().value};
3364ab3302SCarolineConcatto     REAL squares{base};
3464ab3302SCarolineConcatto     int nbits{INT::bits - absPower.LEADZ()};
3564ab3302SCarolineConcatto     for (int j{0}; j < nbits; ++j) {
36*31505c4fSPeter Klausler       if (j > 0) { // avoid spurious overflow on last iteration
37*31505c4fSPeter Klausler         squares =
38*31505c4fSPeter Klausler             squares.Multiply(squares, rounding).AccumulateFlags(result.flags);
39*31505c4fSPeter Klausler       }
4064ab3302SCarolineConcatto       if (absPower.BTEST(j)) {
4164ab3302SCarolineConcatto         if (negativePower) {
4264ab3302SCarolineConcatto           result.value = result.value.Divide(squares, rounding)
4364ab3302SCarolineConcatto                              .AccumulateFlags(result.flags);
4464ab3302SCarolineConcatto         } else {
4564ab3302SCarolineConcatto           result.value = result.value.Multiply(squares, rounding)
4664ab3302SCarolineConcatto                              .AccumulateFlags(result.flags);
4764ab3302SCarolineConcatto         }
4864ab3302SCarolineConcatto       }
4964ab3302SCarolineConcatto     }
5064ab3302SCarolineConcatto   }
5164ab3302SCarolineConcatto   return result;
5264ab3302SCarolineConcatto }
5364ab3302SCarolineConcatto 
5464ab3302SCarolineConcatto template <typename REAL, typename INT>
5523c2bedfSPeter Klausler ValueWithRealFlags<REAL> IntPower(const REAL &base, const INT &power,
5623c2bedfSPeter Klausler     Rounding rounding = TargetCharacteristics::defaultRounding) {
5764ab3302SCarolineConcatto   REAL one{REAL::FromInteger(INT{1}).value};
5864ab3302SCarolineConcatto   return TimesIntPowerOf(one, base, power, rounding);
5964ab3302SCarolineConcatto }
601f879005STim Keith } // namespace Fortran::evaluate
6164ab3302SCarolineConcatto #endif // FORTRAN_EVALUATE_INT_POWER_H_
62