%-----------------------------------------------------------------------------% % vim: ft=mercury ts=4 sw=4 et %-----------------------------------------------------------------------------% % Copyright (C) 1997-1998, 2001, 2005-2006 The University of Melbourne. % Copyright (C) 2015, 2018 The Mercury team. % This file is distributed under the terms specified in COPYING.LIB. %-----------------------------------------------------------------------------% % % File: complex.m. % Main author: fjh. % Stability: medium. % % Complex numbers. % % Note that the overloaded versions of the binary operators that % provide mixed-type arithmetic are defined in other modules. % % See also: % complex_float.m, float_complex.m % imag.m, complex_imag.m, imag_complex.m % %-----------------------------------------------------------------------------% :- module complex_numbers.complex. :- interface. %-----------------------------------------------------------------------------% % The constructor cmplx/2 is made public, but generally it is most convenient % to use the syntax `X + Y*i' for complex numbers, where `i' is declared in % module `imag'. Due to the wonders of logic programming, this works fine for % both constructing and pattern matching; with intermodule optimization % enabled, the compiler should generate equally good code for it. :- type complex ---> cmplx( float, % real part float % imag part ). %-----------------------------------------------------------------------------% % Convert float to complex. % :- func complex(float) = complex. % Extract real part. % :- func real(complex) = float. % Extract imaginary part. % :- func imag(complex) = float. % Square of absolute value. % :- func abs2(complex) = float. % Absolute value (a.k.a. modulus). % :- func abs(complex) = float. % Argument (a.k.a. phase, or amplitude, or angle). % This function returns the principle value: % % for all Z, -pi < arg(Z) and arg(Z) =< pi. % :- func arg(complex) = float. % Complex conjugate. % :- func conj(complex) = complex. % Addition. % :- func complex + complex = complex. :- mode in + in = uo is det. % Subtraction. % :- func complex - complex = complex. :- mode in - in = uo is det. % Multiplication. % :- func complex * complex = complex. :- mode in * in = uo is det. % Division. % :- func complex / complex = complex. :- mode in / in = uo is det. % Unary plus. % :- func + complex = complex. :- mode + in = uo is det. % Unary minus. % :- func - complex = complex. :- mode - in = uo is det. % sqr(X) = X * X. % :- func sqr(complex) = complex. % Square root. % :- func sqrt(complex) = complex. % cis(Theta) = cos(Theta) + i * sin(Theta) % :- func cis(float) = complex. % polar_to_complex(R, Theta). % Conversion from polar coordinates. % :- func polar_to_complex(float, float) = complex. % polar_to_complex(Z, R, Theta). % Conversion to polar coordinates. % :- pred complex_to_polar(complex::in, float::out, float::out) is det. %---------------------------------------------------------------------------% %---------------------------------------------------------------------------% :- implementation. :- import_module float. :- import_module math. %---------------------------------------------------------------------------% complex(Real) = cmplx(Real, 0.0). real(cmplx(Real, _Imag)) = Real. imag(cmplx(_Real, Imag)) = Imag. cmplx(Xr, Xi) + cmplx(Yr, Yi) = cmplx(Xr + Yr, Xi + Yi). cmplx(Xr, Xi) - cmplx(Yr, Yi) = cmplx(Xr - Yr, Xi - Yi). cmplx(Xr, Xi) * cmplx(Yr, Yi) = cmplx(Xr * Yr - Xi * Yi, Xr * Yi + Xi * Yr). cmplx(Xr, Xi) / cmplx(Yr, Yi) = cmplx((Xr * Yr + Xi * Yi) / Div, (Xi * Yr - Xr * Yi) / Div) :- Div = (Yr * Yr + Yi * Yi). % Here's the derivation of the formula for complex division: % cmplx(Xr, Xi) / cmplx(Yr, Yi) = % (cmplx(Xr, Xi) / cmplx(Yr, Yi)) * 1.0 = % (cmplx(Xr, Xi) / cmplx(Yr, Yi)) * (cmplx(Yr, -Yi) / cmplx(Yr, -Yi)) = % (cmplx(Xr, Xi) * (cmplx(Yr, -Yi)) / (cmplx(Yr, Yi) * cmplx(Yr, -Yi)) = % (cmplx(Xr, Xi) * (cmplx(Yr, -Yi)) / (Yr * Yr + Yi * Yi) = % cmplx(Xr * Yr + Xi * Yi, Xi * Yr - Xr * Yi) / (Yr * Yr + Yi * Yi) = % cmplx((Xr * Yr + Xi * Yi) / Div, (Xi * Yr - Xr * Yi) / Div) :- % Div = (Yr * Yr + Yi * Yi). + cmplx(R, I) = cmplx(+ R, + I). - cmplx(R, I) = cmplx(- R, - I). abs2(cmplx(R, I)) = R*R + I*I. abs(Z) = sqrt(abs2(Z)). arg(cmplx(R, I)) = atan2(I, R). conj(cmplx(R, I)) = cmplx(R, -I). sqr(cmplx(Re0, Im0)) = cmplx(Re, Im) :- Re = Re0 * Re0 - Im0 * Im0, Im = 2.0 * Re0 * Im0. sqrt(Z0) = Z :- complex_to_polar(Z0, Magnitude0, Theta0), Magnitude = sqrt(Magnitude0), Theta = Theta0 / 2.0, Z = polar_to_complex(Magnitude, Theta). complex_to_polar(Z, abs(Z), arg(Z)). polar_to_complex(Magnitude, Theta) = cmplx(Real, Imag) :- Real = Magnitude * cos(Theta), Imag = Magnitude * sin(Theta). cis(Theta) = cmplx(cos(Theta), sin(Theta)). %-----------------------------------------------------------------------------% :- end_module complex_numbers.complex. %-----------------------------------------------------------------------------%