FLANG
int-power.h
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/real.h"
15#include "flang/Evaluate/target.h"
16
17namespace Fortran::evaluate {
18
19template <typename REAL, typename INT>
20ValueWithRealFlags<REAL> TimesIntPowerOf(const REAL &factor, const REAL &base,
21 const INT &power, bool forceMultiply = false,
22 Rounding rounding = TargetCharacteristics::defaultRounding) {
23 ValueWithRealFlags<REAL> result{factor};
24 if (base.IsNotANumber()) {
25 result.value = REAL::NotANumber();
26 result.flags.set(RealFlag::InvalidArgument);
27 } else if (power.IsZero()) {
28 if (base.IsZero() || base.IsInfinite()) {
29 result.flags.set(RealFlag::InvalidArgument);
30 }
31 } else {
32 bool negativePower{!forceMultiply && power.IsNegative()};
33 INT absPower{power.ABS().value};
34 REAL squares{base};
35 int nbits{INT::bits - absPower.LEADZ()};
36 for (int j{0}; j < nbits; ++j) {
37 if (j > 0) { // avoid spurious overflow on last iteration
38 squares =
39 squares.Multiply(squares, rounding).AccumulateFlags(result.flags);
40 }
41 if (absPower.BTEST(j)) {
42 if (negativePower) {
43 result.value = result.value.Divide(squares, rounding)
44 .AccumulateFlags(result.flags);
45 } else {
46 result.value = result.value.Multiply(squares, rounding)
47 .AccumulateFlags(result.flags);
48 }
49 }
50 }
51 }
52 return result;
53}
54
55template <typename W, int P, typename INT>
57 const INT &power,
58 Rounding rounding = TargetCharacteristics::defaultRounding) {
59 using REAL = value::Real<W, P>;
60 REAL one{REAL::FromInteger(INT{1}).value};
62 TimesIntPowerOf(one, base, power, /*forceMultiply=*/false, rounding)};
63 if (result.flags.test(RealFlag::Overflow) && power.IsNegative() &&
64 !base.IsZero() && base.ABS().Compare(one) == Relation::Greater) {
66 REAL recip{one.Divide(base, rounding).AccumulateFlags(retry.flags)};
67 retry.value =
68 TimesIntPowerOf(one, recip, power, /*forceMultiply=*/true, rounding)
69 .AccumulateFlags(retry.flags);
70 return retry;
71 }
72 return result;
73}
74
75template <typename REAL, typename INT>
76ValueWithRealFlags<REAL> IntPower(const REAL &base, const INT &power,
77 Rounding rounding = TargetCharacteristics::defaultRounding) {
78 REAL one{REAL::FromInteger(INT{1}).value};
79 return TimesIntPowerOf(one, base, power, /*forceMultiply=*/false, rounding);
80}
81} // namespace Fortran::evaluate
82#endif // FORTRAN_EVALUATE_INT_POWER_H_
Definition real.h:44
Definition call.h:34
Definition target-rounding.h:18