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