1 //===-- include/flang/Evaluate/complex.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_COMPLEX_H_
10 #define FORTRAN_EVALUATE_COMPLEX_H_
11 
12 #include "formatting.h"
13 #include "real.h"
14 #include <string>
15 
16 namespace llvm {
17 class raw_ostream;
18 }
19 
20 namespace Fortran::evaluate::value {
21 
22 template <typename REAL_TYPE> class Complex {
23 public:
24   using Part = REAL_TYPE;
25   static constexpr int bits{2 * Part::bits};
26 
Complex()27   constexpr Complex() {} // (+0.0, +0.0)
28   constexpr Complex(const Complex &) = default;
Complex(const Part & r,const Part & i)29   constexpr Complex(const Part &r, const Part &i) : re_{r}, im_{i} {}
Complex(const Part & r)30   explicit constexpr Complex(const Part &r) : re_{r} {}
31   constexpr Complex &operator=(const Complex &) = default;
32   constexpr Complex &operator=(Complex &&) = default;
33 
34   constexpr bool operator==(const Complex &that) const {
35     return re_ == that.re_ && im_ == that.im_;
36   }
37 
REAL()38   constexpr const Part &REAL() const { return re_; }
AIMAG()39   constexpr const Part &AIMAG() const { return im_; }
CONJG()40   constexpr Complex CONJG() const { return {re_, im_.Negate()}; }
Negate()41   constexpr Complex Negate() const { return {re_.Negate(), im_.Negate()}; }
42 
Equals(const Complex & that)43   constexpr bool Equals(const Complex &that) const {
44     return re_.Compare(that.re_) == Relation::Equal &&
45         im_.Compare(that.im_) == Relation::Equal;
46   }
47 
IsZero()48   constexpr bool IsZero() const { return re_.IsZero() || im_.IsZero(); }
49 
IsInfinite()50   constexpr bool IsInfinite() const {
51     return re_.IsInfinite() || im_.IsInfinite();
52   }
53 
IsNotANumber()54   constexpr bool IsNotANumber() const {
55     return re_.IsNotANumber() || im_.IsNotANumber();
56   }
57 
IsSignalingNaN()58   constexpr bool IsSignalingNaN() const {
59     return re_.IsSignalingNaN() || im_.IsSignalingNaN();
60   }
61 
62   template <typename INT>
63   static ValueWithRealFlags<Complex> FromInteger(
64       const INT &n, Rounding rounding = defaultRounding) {
65     ValueWithRealFlags<Complex> result;
66     result.value.re_ =
67         Part::FromInteger(n, rounding).AccumulateFlags(result.flags);
68     return result;
69   }
70 
71   ValueWithRealFlags<Complex> Add(
72       const Complex &, Rounding rounding = defaultRounding) const;
73   ValueWithRealFlags<Complex> Subtract(
74       const Complex &, Rounding rounding = defaultRounding) const;
75   ValueWithRealFlags<Complex> Multiply(
76       const Complex &, Rounding rounding = defaultRounding) const;
77   ValueWithRealFlags<Complex> Divide(
78       const Complex &, Rounding rounding = defaultRounding) const;
79 
FlushSubnormalToZero()80   constexpr Complex FlushSubnormalToZero() const {
81     return {re_.FlushSubnormalToZero(), im_.FlushSubnormalToZero()};
82   }
83 
NotANumber()84   static constexpr Complex NotANumber() {
85     return {Part::NotANumber(), Part::NotANumber()};
86   }
87 
88   std::string DumpHexadecimal() const;
89   llvm::raw_ostream &AsFortran(llvm::raw_ostream &, int kind) const;
90 
91   // TODO: (C)ABS once Real::HYPOT is done
92   // TODO: unit testing
93 
94 private:
95   Part re_, im_;
96 };
97 
98 extern template class Complex<Real<Integer<16>, 11>>;
99 extern template class Complex<Real<Integer<16>, 8>>;
100 extern template class Complex<Real<Integer<32>, 24>>;
101 extern template class Complex<Real<Integer<64>, 53>>;
102 extern template class Complex<Real<Integer<80>, 64>>;
103 extern template class Complex<Real<Integer<128>, 113>>;
104 } // namespace Fortran::evaluate::value
105 #endif // FORTRAN_EVALUATE_COMPLEX_H_
106