xref: /llvm-project/flang/lib/Evaluate/complex.cpp (revision 1444e5acfb75630c23b118c39454a05cf3792d35)
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)]
502b5cd377SPeter Klausler   //   -> [ac+bd+i(bc-ad)] / (cc+dd)  -- note (cc+dd) is real
5164ab3302SCarolineConcatto   //   -> ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd))
5264ab3302SCarolineConcatto   RealFlags flags;
532b5cd377SPeter Klausler   Part cc{that.re_.Multiply(that.re_, rounding).AccumulateFlags(flags)};
542b5cd377SPeter Klausler   Part dd{that.im_.Multiply(that.im_, rounding).AccumulateFlags(flags)};
552b5cd377SPeter Klausler   Part ccPdd{cc.Add(dd, rounding).AccumulateFlags(flags)};
562b5cd377SPeter Klausler   if (!flags.test(RealFlag::Overflow) && !flags.test(RealFlag::Underflow)) {
572b5cd377SPeter Klausler     // den = (cc+dd) did not overflow or underflow; try the naive
582b5cd377SPeter Klausler     // sequence without scaling to avoid extra roundings.
592b5cd377SPeter Klausler     Part ac{re_.Multiply(that.re_, rounding).AccumulateFlags(flags)};
602b5cd377SPeter Klausler     Part ad{re_.Multiply(that.im_, rounding).AccumulateFlags(flags)};
612b5cd377SPeter Klausler     Part bc{im_.Multiply(that.re_, rounding).AccumulateFlags(flags)};
622b5cd377SPeter Klausler     Part bd{im_.Multiply(that.im_, rounding).AccumulateFlags(flags)};
632b5cd377SPeter Klausler     Part acPbd{ac.Add(bd, rounding).AccumulateFlags(flags)};
642b5cd377SPeter Klausler     Part bcSad{bc.Subtract(ad, rounding).AccumulateFlags(flags)};
652b5cd377SPeter Klausler     Part re{acPbd.Divide(ccPdd, rounding).AccumulateFlags(flags)};
662b5cd377SPeter Klausler     Part im{bcSad.Divide(ccPdd, rounding).AccumulateFlags(flags)};
672b5cd377SPeter Klausler     if (!flags.test(RealFlag::Overflow) && !flags.test(RealFlag::Underflow)) {
682b5cd377SPeter Klausler       return {Complex{re, im}, flags};
692b5cd377SPeter Klausler     }
702b5cd377SPeter Klausler   }
712b5cd377SPeter Klausler   // Scale numerator and denominator by d/c (if c>=d) or c/d (if c<d)
722b5cd377SPeter Klausler   flags.clear();
732b5cd377SPeter Klausler   Part scale; // will be <= 1.0 in magnitude
7464ab3302SCarolineConcatto   bool cGEd{that.re_.ABS().Compare(that.im_.ABS()) != Relation::Less};
7564ab3302SCarolineConcatto   if (cGEd) {
7664ab3302SCarolineConcatto     scale = that.im_.Divide(that.re_, rounding).AccumulateFlags(flags);
7764ab3302SCarolineConcatto   } else {
7864ab3302SCarolineConcatto     scale = that.re_.Divide(that.im_, rounding).AccumulateFlags(flags);
7964ab3302SCarolineConcatto   }
8064ab3302SCarolineConcatto   Part den;
8164ab3302SCarolineConcatto   if (cGEd) {
8264ab3302SCarolineConcatto     Part dS{scale.Multiply(that.im_, rounding).AccumulateFlags(flags)};
8364ab3302SCarolineConcatto     den = dS.Add(that.re_, rounding).AccumulateFlags(flags);
8464ab3302SCarolineConcatto   } else {
8564ab3302SCarolineConcatto     Part cS{scale.Multiply(that.re_, rounding).AccumulateFlags(flags)};
8664ab3302SCarolineConcatto     den = cS.Add(that.im_, rounding).AccumulateFlags(flags);
8764ab3302SCarolineConcatto   }
8864ab3302SCarolineConcatto   Part aS{scale.Multiply(re_, rounding).AccumulateFlags(flags)};
8964ab3302SCarolineConcatto   Part bS{scale.Multiply(im_, rounding).AccumulateFlags(flags)};
9064ab3302SCarolineConcatto   Part re1, im1;
9164ab3302SCarolineConcatto   if (cGEd) {
9264ab3302SCarolineConcatto     re1 = re_.Add(bS, rounding).AccumulateFlags(flags);
9364ab3302SCarolineConcatto     im1 = im_.Subtract(aS, rounding).AccumulateFlags(flags);
9464ab3302SCarolineConcatto   } else {
9564ab3302SCarolineConcatto     re1 = aS.Add(im_, rounding).AccumulateFlags(flags);
9664ab3302SCarolineConcatto     im1 = bS.Subtract(re_, rounding).AccumulateFlags(flags);
9764ab3302SCarolineConcatto   }
9864ab3302SCarolineConcatto   Part re{re1.Divide(den, rounding).AccumulateFlags(flags)};
9964ab3302SCarolineConcatto   Part im{im1.Divide(den, rounding).AccumulateFlags(flags)};
10064ab3302SCarolineConcatto   return {Complex{re, im}, flags};
10164ab3302SCarolineConcatto }
10264ab3302SCarolineConcatto 
DumpHexadecimal() const10364ab3302SCarolineConcatto template <typename R> std::string Complex<R>::DumpHexadecimal() const {
10464ab3302SCarolineConcatto   std::string result{'('};
10564ab3302SCarolineConcatto   result += re_.DumpHexadecimal();
10664ab3302SCarolineConcatto   result += ',';
10764ab3302SCarolineConcatto   result += im_.DumpHexadecimal();
10864ab3302SCarolineConcatto   result += ')';
10964ab3302SCarolineConcatto   return result;
11064ab3302SCarolineConcatto }
11164ab3302SCarolineConcatto 
11264ab3302SCarolineConcatto template <typename R>
AsFortran(llvm::raw_ostream & o,int kind) const1138670e499SCaroline Concatto llvm::raw_ostream &Complex<R>::AsFortran(llvm::raw_ostream &o, int kind) const {
11464ab3302SCarolineConcatto   re_.AsFortran(o << '(', kind);
11564ab3302SCarolineConcatto   im_.AsFortran(o << ',', kind);
11664ab3302SCarolineConcatto   return o << ')';
11764ab3302SCarolineConcatto }
11864ab3302SCarolineConcatto 
11964ab3302SCarolineConcatto template class Complex<Real<Integer<16>, 11>>;
12064ab3302SCarolineConcatto template class Complex<Real<Integer<16>, 8>>;
12164ab3302SCarolineConcatto template class Complex<Real<Integer<32>, 24>>;
12264ab3302SCarolineConcatto template class Complex<Real<Integer<64>, 53>>;
123*1444e5acSPeter Klausler template class Complex<Real<X87IntegerContainer, 64>>;
124b7a5b5c7Speter klausler template class Complex<Real<Integer<128>, 113>>;
1251f879005STim Keith } // namespace Fortran::evaluate::value
126