Fuzion Logo
flang.dev — The Fuzion Language Portal
JavaScript seems to be disabled. Functionality is limited.

complex.fz


# This file is part of the Fuzion language implementation.
#
# The Fuzion language implementation is free software: you can redistribute it
# and/or modify it under the terms of the GNU General Public License as published
# by the Free Software Foundation, version 3 of the License.
#
# The Fuzion language implementation is distributed in the hope that it will be
# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
# License for more details.
#
# You should have received a copy of the GNU General Public License along with The
# Fuzion language implementation.  If not, see <https://www.gnu.org/licenses/>.


# -----------------------------------------------------------------------
#
#  Tokiwa Software GmbH, Germany
#
#  Source code of Fuzion standard library feature complex
#
#  Author: Fridtjof Siebert (siebert@tokiwa.software)
#
# -----------------------------------------------------------------------

# complex -- complex numbers based on arbitrary numeric type
#
# complex provides complex numbers based on a numeric type (e.g. f64, i32).
# A complex number consists of a real and an imaginary part.
#
complex (C numeric<C>.type,
         real,    # real part
         imag C   # imaginary part
         ) : numeric<complex<C>>, complexes<C>
is

# private:

  # just for brevity
  a => complex real imag

# public:

  # enable generic features in ancestors
  redef thiz => a
  redef orderedThis => a

  # basic operations
  redef prefix + => a
  redef infix +  (b complex<C>) => complex a.real+b.real a.imag+b.imag
  redef infix -  (b complex<C>) => complex a.real-b.real a.imag-b.imag
  redef infix *  (b complex<C>) => complex a.real*b.real-a.imag*b.imag a.real*b.imag+a.imag*b.real
  redef infix /  (b complex<C>) complex<C>
    pre
      safety: b != zero
  is
    n := b.real*b.real+b.imag*b.imag
    complex (a.real*b.real+a.imag*b.imag)/n (a.imag*b.real-a.real*b.imag)/n

  # comparison
  redef infix == (b complex<C>) => a.real  = b.real && a.imag  = b.imag
  redef infix != (b complex<C>) => a.real != b.real || a.imag != b.imag

  # NYI: total order ignoring imag
  redef infix <  (b complex<C>) => a.real <  b.real
  redef infix <= (b complex<C>) => a.real <= b.real
  redef infix >  (b complex<C>) => a.real >  b.real
  redef infix >= (b complex<C>) => a.real >= b.real

  abs² => real*real+imag*imag

  redef asString =>
    si :=
      for c in ($imag).asCodepoints
      until !("0123456789.+-".contains c)
        "($imag)"
      else
        $imag
    p := if (si.startsWith "-") then "" else "+"
    "{real}$p{si}i"

  # NYI: these three should be implemented in complexes, not here:
  redef zero => complex real.zero real.zero
  redef one  => complex real.one real.zero
  i => complex real.zero real.one


# complexes -- unit type defining features related to complex
#
# complexes is a unit type defining features related to complex but not
# requiring an instance.
#
# The plural form of complex is complexes or complices (archaic), according
# to https://www.wordhippo.com/what-is/the-plural-of/complex.html, so we
# use complexes.
#
complexes<E : numeric<E>> : numerics<complex<E>> is

  redef name => "complex"

  # NYI: There is currently no easy way to get hold of an instance of the unit
  # type corresponding to E.
  #
  #   redef zero => complex E.zero E.zero
  #   redef one  => complex E.one  E.zero
  #
  # dummy implementations:
  # redef zero => panic "NYI: complexes.zero not implemented, needs to instantiate type arg E"
  # redef one  => panic "NYI: complexes.one not implemented, needs to instantiate type arg E"


# complex -- returns value of unit type complexes
#
# This is a convenience feature that allows using, e.g.,
# 'complex<i32>.sum' to get the the monoid of (complex, infix +) instead of
# 'complexs.sum'.
#
# Since this complex with no arguments is a routine and not a constructor, it
# does not define a type (which would cause a name clash with complex with two
# arguments).
#
complex<E: numeric<E>> => complexes<E>