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