62 lines · c
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-exception6//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 16namespace Fortran::evaluate {17 18template <typename REAL, typename INT>19ValueWithRealFlags<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 iteration37 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 54template <typename REAL, typename INT>55ValueWithRealFlags<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::evaluate61#endif // FORTRAN_EVALUATE_INT_POWER_H_62