Merge pull request #778 from cmorris98/master
[mono.git] / mcs / class / dlr / Runtime / Microsoft.Dynamic / Math / Complex64.cs
1 /* ****************************************************************************
2  *
3  * Copyright (c) Microsoft Corporation. 
4  *
5  * This source code is subject to terms and conditions of the Apache License, Version 2.0. A 
6  * copy of the license can be found in the License.html file at the root of this distribution. If 
7  * you cannot locate the  Apache License, Version 2.0, please send an email to 
8  * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
9  * by the terms of the Apache License, Version 2.0.
10  *
11  * You must not remove this notice, or any other, from this software.
12  *
13  *
14  * ***************************************************************************/
15
16 using System;
17 using Microsoft.Scripting.Utils;
18
19 #if FEATURE_NUMERICS
20 using BigInt = System.Numerics.BigInteger;
21 #endif
22
23 namespace Microsoft.Scripting.Math {
24     /// <summary>
25     /// Implementation of the complex number data type.
26     /// </summary>
27     [Serializable]
28     public struct Complex64 {
29         public static readonly Complex64 Zero = new Complex64(0.0, 0.0);
30         public static readonly Complex64 One = new Complex64(1.0, 0.0);
31         public static readonly Complex64 ImaginaryOne = new Complex64(0.0, 1.0);
32
33         private readonly double real, imag;
34
35         public static Complex64 MakeImaginary(double imag) {
36             return new Complex64(0.0, imag);
37         }
38
39         public static Complex64 MakeReal(double real) {
40             return new Complex64(real, 0.0);
41         }
42
43         public static Complex64 Make(double real, double imag) {
44             return new Complex64(real, imag);
45         }
46
47         public Complex64(double real)
48             : this(real, 0.0) {
49         }
50
51         public Complex64(double real, double imag) {
52             this.real = real;
53             this.imag = imag;
54         }
55
56         public bool IsZero {
57             get {
58                 return real == 0.0 && imag == 0.0;
59             }
60         }
61
62         public double Real {
63             get {
64                 return real;
65             }
66         }
67
68         public double Imag {
69             get {
70                 return imag;
71             }
72         }
73
74         public Complex64 Conjugate() {
75             return new Complex64(real, -imag);
76         }
77
78
79         public override string ToString() {
80             if (real == 0.0) return imag.ToString(System.Globalization.CultureInfo.InvariantCulture.NumberFormat) + "j";
81             else if (imag < 0.0) return string.Format(System.Globalization.CultureInfo.InvariantCulture.NumberFormat, "({0}{1}j)", real, imag);
82             else return string.Format(System.Globalization.CultureInfo.InvariantCulture.NumberFormat, "({0}+{1}j)", real, imag);
83         }
84
85         public static implicit operator Complex64(bool b) {
86             return b ? One : Zero;
87         }
88
89         public static implicit operator Complex64(int i) {
90             return MakeReal(i);
91         }
92
93         [CLSCompliant(false)]
94         public static implicit operator Complex64(uint i) {
95             return MakeReal(i);
96         }
97
98         public static implicit operator Complex64(short i) {
99             return MakeReal(i);
100         }
101         
102         [CLSCompliant(false)]
103         public static implicit operator Complex64(ushort i) {
104             return MakeReal(i);
105         }
106
107         public static implicit operator Complex64(long l) {
108             return MakeReal(l);
109         }
110         [CLSCompliant(false)]
111         public static implicit operator Complex64(ulong i) {
112             return MakeReal(i);
113         }
114
115         [CLSCompliant(false)]
116         public static implicit operator Complex64(sbyte i) {
117             return MakeReal(i);
118         }
119
120         public static implicit operator Complex64(byte i) {
121             return MakeReal(i);
122         }
123
124         public static implicit operator Complex64(float f) {
125             return MakeReal(f);
126         }
127
128         public static implicit operator Complex64(double d) {
129             return MakeReal(d);
130         }
131
132         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1065:DoNotRaiseExceptionsInUnexpectedLocations")] // TODO: fix
133         public static implicit operator Complex64(BigInteger i) {
134             ContractUtils.RequiresNotNull(i, "i");
135
136             // throws an overflow exception if we can't handle the value.
137             return MakeReal((double)i);
138         }
139
140 #if FEATURE_NUMERICS
141         public static implicit operator Complex64(BigInt i) {
142             // throws an overflow exception if we can't handle the value.
143             return MakeReal((double)i);
144         }
145 #endif
146
147         public static bool operator ==(Complex64 x, Complex64 y) {
148             return x.real == y.real && x.imag == y.imag;
149         }
150
151         public static bool operator !=(Complex64 x, Complex64 y) {
152             return x.real != y.real || x.imag != y.imag;
153         }
154
155         public static Complex64 Add(Complex64 x, Complex64 y) {
156             return x + y;
157         }
158
159         public static Complex64 operator +(Complex64 x, Complex64 y) {
160             return new Complex64(x.real + y.real, x.imag + y.imag);
161         }
162
163         public static Complex64 Subtract(Complex64 x, Complex64 y) {
164             return x - y;
165         }
166
167         public static Complex64 operator -(Complex64 x, Complex64 y) {
168             return new Complex64(x.real - y.real, x.imag - y.imag);
169         }
170
171         public static Complex64 Multiply(Complex64 x, Complex64 y) {
172             return x * y;
173         }
174
175         public static Complex64 operator *(Complex64 x, Complex64 y) {
176             return new Complex64(x.real * y.real - x.imag * y.imag, x.real * y.imag + x.imag * y.real);
177         }
178
179         public static Complex64 Divide(Complex64 x, Complex64 y) {
180             return x / y;
181         }
182
183         public static Complex64 operator /(Complex64 a, Complex64 b) {
184             if (b.IsZero) {
185                 throw new DivideByZeroException("complex division by zero");
186             }
187
188             double real, imag, den, r;
189
190             if (System.Math.Abs(b.real) >= System.Math.Abs(b.imag)) {
191                 r = b.imag / b.real;
192                 den = b.real + r * b.imag;
193                 real = (a.real + a.imag * r) / den;
194                 imag = (a.imag - a.real * r) / den;
195             } else {
196                 r = b.real / b.imag;
197                 den = b.imag + r * b.real;
198                 real = (a.real * r + a.imag) / den;
199                 imag = (a.imag * r - a.real) / den;
200             }
201
202             return new Complex64(real, imag);
203         }
204
205         public static Complex64 Negate(Complex64 x) {
206             return -x;
207         }
208
209         public static Complex64 operator -(Complex64 x) {
210             return new Complex64(-x.real, -x.imag);
211         }
212
213         public static Complex64 Plus(Complex64 x) {
214             return +x;
215         }
216
217         public static Complex64 operator +(Complex64 x) {
218             return x;
219         }
220         
221         [Obsolete("Deprecated - consider using MS.Scripting.Utils.MathUtils.Hypot")]
222         public static double Hypot(double x, double y) {
223             return MathUtils.Hypot(x, y);
224         }
225
226         public double Abs() {
227             return MathUtils.Hypot(real, imag);
228         }
229
230         public Complex64 Power(Complex64 y) {
231             double c = y.real;
232             double d = y.imag;
233             int power = (int)c;
234
235             if (power == c && power >= 0 && d == .0) {
236                 Complex64 result = One;
237                 if (power == 0) return result;
238                 Complex64 factor = this;
239                 while (power != 0) {
240                     if ((power & 1) != 0) {
241                         result = result * factor;
242                     }
243                     factor = factor * factor;
244                     power >>= 1;
245                 }
246                 return result;
247             } else if (IsZero) {
248                 return y.IsZero ? One : Zero;
249             } else {
250                 double a = real;
251                 double b = imag;
252                 double powers = a * a + b * b;
253                 double arg = System.Math.Atan2(b, a);
254                 double mul = System.Math.Pow(powers, c / 2) * System.Math.Exp(-d * arg);
255                 double common = c * arg + .5 * d * System.Math.Log(powers);
256                 return new Complex64(mul * System.Math.Cos(common), mul * System.Math.Sin(common));
257             }
258         }
259
260         public override int GetHashCode() {
261             // The Object.GetHashCode function needs to be consistent with the Object.Equals function.
262             // Languages that build on top of this may have a more flexible equality function and 
263             // so may not be able to use this hash function directly.
264             // For example, Python allows that c=Complex64(1.5, 0), f = 1.5f,  c==f.
265             // so then the hash(f) == hash(c). Since the python (and other languages) can define an arbitrary
266             // hash(float) function, the language may need to define a matching hash(complex) function for
267             // the cases where the float and complex numbers overlap.
268             return (int)real + (int)imag * 1000003;
269         }
270
271         public override bool Equals(object obj) {
272             if (!(obj is Complex64)) return false;
273             return this == ((Complex64)obj);
274         }
275     }
276 }