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