164ab3302SCarolineConcatto //===-- lib/Evaluate/complex.cpp ------------------------------------------===//
264ab3302SCarolineConcatto //
364ab3302SCarolineConcatto // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
464ab3302SCarolineConcatto // See https://llvm.org/LICENSE.txt for license information.
564ab3302SCarolineConcatto // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
664ab3302SCarolineConcatto //
764ab3302SCarolineConcatto //===----------------------------------------------------------------------===//
864ab3302SCarolineConcatto
964ab3302SCarolineConcatto #include "flang/Evaluate/complex.h"
108670e499SCaroline Concatto #include "llvm/Support/raw_ostream.h"
1164ab3302SCarolineConcatto
1264ab3302SCarolineConcatto namespace Fortran::evaluate::value {
1364ab3302SCarolineConcatto
1464ab3302SCarolineConcatto template <typename R>
Add(const Complex & that,Rounding rounding) const1564ab3302SCarolineConcatto ValueWithRealFlags<Complex<R>> Complex<R>::Add(
1664ab3302SCarolineConcatto const Complex &that, Rounding rounding) const {
1764ab3302SCarolineConcatto RealFlags flags;
1864ab3302SCarolineConcatto Part reSum{re_.Add(that.re_, rounding).AccumulateFlags(flags)};
1964ab3302SCarolineConcatto Part imSum{im_.Add(that.im_, rounding).AccumulateFlags(flags)};
2064ab3302SCarolineConcatto return {Complex{reSum, imSum}, flags};
2164ab3302SCarolineConcatto }
2264ab3302SCarolineConcatto
2364ab3302SCarolineConcatto template <typename R>
Subtract(const Complex & that,Rounding rounding) const2464ab3302SCarolineConcatto ValueWithRealFlags<Complex<R>> Complex<R>::Subtract(
2564ab3302SCarolineConcatto const Complex &that, Rounding rounding) const {
2664ab3302SCarolineConcatto RealFlags flags;
2764ab3302SCarolineConcatto Part reDiff{re_.Subtract(that.re_, rounding).AccumulateFlags(flags)};
2864ab3302SCarolineConcatto Part imDiff{im_.Subtract(that.im_, rounding).AccumulateFlags(flags)};
2964ab3302SCarolineConcatto return {Complex{reDiff, imDiff}, flags};
3064ab3302SCarolineConcatto }
3164ab3302SCarolineConcatto
3264ab3302SCarolineConcatto template <typename R>
Multiply(const Complex & that,Rounding rounding) const3364ab3302SCarolineConcatto ValueWithRealFlags<Complex<R>> Complex<R>::Multiply(
3464ab3302SCarolineConcatto const Complex &that, Rounding rounding) const {
3564ab3302SCarolineConcatto // (a + ib)*(c + id) -> ac - bd + i(ad + bc)
3664ab3302SCarolineConcatto RealFlags flags;
3764ab3302SCarolineConcatto Part ac{re_.Multiply(that.re_, rounding).AccumulateFlags(flags)};
3864ab3302SCarolineConcatto Part bd{im_.Multiply(that.im_, rounding).AccumulateFlags(flags)};
3964ab3302SCarolineConcatto Part ad{re_.Multiply(that.im_, rounding).AccumulateFlags(flags)};
4064ab3302SCarolineConcatto Part bc{im_.Multiply(that.re_, rounding).AccumulateFlags(flags)};
4164ab3302SCarolineConcatto Part acbd{ac.Subtract(bd, rounding).AccumulateFlags(flags)};
4264ab3302SCarolineConcatto Part adbc{ad.Add(bc, rounding).AccumulateFlags(flags)};
4364ab3302SCarolineConcatto return {Complex{acbd, adbc}, flags};
4464ab3302SCarolineConcatto }
4564ab3302SCarolineConcatto
4664ab3302SCarolineConcatto template <typename R>
Divide(const Complex & that,Rounding rounding) const4764ab3302SCarolineConcatto ValueWithRealFlags<Complex<R>> Complex<R>::Divide(
4864ab3302SCarolineConcatto const Complex &that, Rounding rounding) const {
4964ab3302SCarolineConcatto // (a + ib)/(c + id) -> [(a+ib)*(c-id)] / [(c+id)*(c-id)]
5064ab3302SCarolineConcatto // -> [ac+bd+i(bc-ad)] / (cc+dd)
5164ab3302SCarolineConcatto // -> ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd))
5264ab3302SCarolineConcatto // but to avoid overflows, scale by d/c if c>=d, else c/d
5364ab3302SCarolineConcatto Part scale; // <= 1.0
5464ab3302SCarolineConcatto RealFlags flags;
5564ab3302SCarolineConcatto bool cGEd{that.re_.ABS().Compare(that.im_.ABS()) != Relation::Less};
5664ab3302SCarolineConcatto if (cGEd) {
5764ab3302SCarolineConcatto scale = that.im_.Divide(that.re_, rounding).AccumulateFlags(flags);
5864ab3302SCarolineConcatto } else {
5964ab3302SCarolineConcatto scale = that.re_.Divide(that.im_, rounding).AccumulateFlags(flags);
6064ab3302SCarolineConcatto }
6164ab3302SCarolineConcatto Part den;
6264ab3302SCarolineConcatto if (cGEd) {
6364ab3302SCarolineConcatto Part dS{scale.Multiply(that.im_, rounding).AccumulateFlags(flags)};
6464ab3302SCarolineConcatto den = dS.Add(that.re_, rounding).AccumulateFlags(flags);
6564ab3302SCarolineConcatto } else {
6664ab3302SCarolineConcatto Part cS{scale.Multiply(that.re_, rounding).AccumulateFlags(flags)};
6764ab3302SCarolineConcatto den = cS.Add(that.im_, rounding).AccumulateFlags(flags);
6864ab3302SCarolineConcatto }
6964ab3302SCarolineConcatto Part aS{scale.Multiply(re_, rounding).AccumulateFlags(flags)};
7064ab3302SCarolineConcatto Part bS{scale.Multiply(im_, rounding).AccumulateFlags(flags)};
7164ab3302SCarolineConcatto Part re1, im1;
7264ab3302SCarolineConcatto if (cGEd) {
7364ab3302SCarolineConcatto re1 = re_.Add(bS, rounding).AccumulateFlags(flags);
7464ab3302SCarolineConcatto im1 = im_.Subtract(aS, rounding).AccumulateFlags(flags);
7564ab3302SCarolineConcatto } else {
7664ab3302SCarolineConcatto re1 = aS.Add(im_, rounding).AccumulateFlags(flags);
7764ab3302SCarolineConcatto im1 = bS.Subtract(re_, rounding).AccumulateFlags(flags);
7864ab3302SCarolineConcatto }
7964ab3302SCarolineConcatto Part re{re1.Divide(den, rounding).AccumulateFlags(flags)};
8064ab3302SCarolineConcatto Part im{im1.Divide(den, rounding).AccumulateFlags(flags)};
8164ab3302SCarolineConcatto return {Complex{re, im}, flags};
8264ab3302SCarolineConcatto }
8364ab3302SCarolineConcatto
DumpHexadecimal() const8464ab3302SCarolineConcatto template <typename R> std::string Complex<R>::DumpHexadecimal() const {
8564ab3302SCarolineConcatto std::string result{'('};
8664ab3302SCarolineConcatto result += re_.DumpHexadecimal();
8764ab3302SCarolineConcatto result += ',';
8864ab3302SCarolineConcatto result += im_.DumpHexadecimal();
8964ab3302SCarolineConcatto result += ')';
9064ab3302SCarolineConcatto return result;
9164ab3302SCarolineConcatto }
9264ab3302SCarolineConcatto
9364ab3302SCarolineConcatto template <typename R>
AsFortran(llvm::raw_ostream & o,int kind) const948670e499SCaroline Concatto llvm::raw_ostream &Complex<R>::AsFortran(llvm::raw_ostream &o, int kind) const {
9564ab3302SCarolineConcatto re_.AsFortran(o << '(', kind);
9664ab3302SCarolineConcatto im_.AsFortran(o << ',', kind);
9764ab3302SCarolineConcatto return o << ')';
9864ab3302SCarolineConcatto }
9964ab3302SCarolineConcatto
10064ab3302SCarolineConcatto template class Complex<Real<Integer<16>, 11>>;
10164ab3302SCarolineConcatto template class Complex<Real<Integer<16>, 8>>;
10264ab3302SCarolineConcatto template class Complex<Real<Integer<32>, 24>>;
10364ab3302SCarolineConcatto template class Complex<Real<Integer<64>, 53>>;
10464ab3302SCarolineConcatto template class Complex<Real<Integer<80>, 64>>;
105b7a5b5c7Speter klausler template class Complex<Real<Integer<128>, 113>>;
106*1f879005STim Keith } // namespace Fortran::evaluate::value
107