PageRenderTime 28ms CodeModel.GetById 9ms app.highlight 14ms RepoModel.GetById 1ms app.codeStats 0ms

/IronPython_Main/Languages/IronPython/IronPython/Runtime/Operations/ComplexOps.cs

#
C# | 339 lines | 259 code | 50 blank | 30 comment | 65 complexity | 2e2f88592d0e3f97ecb3cfa15166526a MD5 | raw file
  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
 16using System;
 17using System.Runtime.CompilerServices;
 18using System.Runtime.InteropServices;
 19using Microsoft.Scripting.Runtime;
 20using Microsoft.Scripting.Utils;
 21using IronPython.Runtime.Exceptions;
 22using IronPython.Runtime.Types;
 23
 24#if CLR2
 25using Microsoft.Scripting.Math;
 26using Complex = Microsoft.Scripting.Math.Complex64;
 27#else
 28using System.Numerics;
 29#endif
 30
 31namespace IronPython.Runtime.Operations {
 32    public class ExtensibleComplex : Extensible<Complex> {
 33        public ExtensibleComplex() : base() { }
 34        public ExtensibleComplex(double real) : base(MathUtils.MakeReal(real)) { }
 35        public ExtensibleComplex(double real, double imag) : base(new Complex(real, imag)) { }
 36    }
 37
 38    public static partial class ComplexOps {
 39        [StaticExtensionMethod]
 40        public static object __new__(CodeContext context, PythonType cls) {
 41            if (cls == TypeCache.Complex) return new Complex();
 42            return cls.CreateInstance(context);
 43        }
 44
 45        [StaticExtensionMethod]
 46        public static object __new__(
 47            CodeContext context, 
 48            PythonType cls,
 49            [DefaultParameterValue(null)]object real,
 50            [DefaultParameterValue(null)]object imag
 51           ) {
 52            Complex real2, imag2;
 53            real2 = imag2 = new Complex();
 54
 55            if (real == null && imag == null && cls == TypeCache.Complex) throw PythonOps.TypeError("argument must be a string or a number");
 56
 57            if (imag != null) {
 58                if (real is string) throw PythonOps.TypeError("complex() can't take second arg if first is a string");
 59                if (imag is string) throw PythonOps.TypeError("complex() second arg can't be a string");
 60                imag2 = Converter.ConvertToComplex(imag);
 61            }
 62
 63            if (real != null) {
 64                if (real is string) {
 65                    real2 = LiteralParser.ParseComplex((string)real);
 66                } else if (real is Extensible<string>) {
 67                    real2 = LiteralParser.ParseComplex(((Extensible<string>)real).Value);
 68                } else if (real is Complex) {
 69                    if (imag == null && cls == TypeCache.Complex) return real;
 70                    else real2 = (Complex)real;
 71                } else {
 72                    real2 = Converter.ConvertToComplex(real);
 73                }
 74            }
 75
 76            double real3 = real2.Real - imag2.Imaginary();
 77            double imag3 = real2.Imaginary() + imag2.Real;
 78            if (cls == TypeCache.Complex) {
 79                return new Complex(real3, imag3);
 80            } else {
 81                return cls.CreateInstance(context, real3, imag3);
 82            }
 83        }
 84        
 85        [StaticExtensionMethod]
 86        public static object __new__(CodeContext context, PythonType cls, double real) {
 87            if (cls == TypeCache.Complex) {
 88                return new Complex(real, 0.0);
 89            } else {
 90                return cls.CreateInstance(context, real, 0.0);
 91            }
 92        }
 93
 94        [StaticExtensionMethod]
 95        public static object __new__(CodeContext context, PythonType cls, double real, double imag) {
 96            if (cls == TypeCache.Complex) {
 97                return new Complex(real, imag);
 98            } else {
 99                return cls.CreateInstance(context, real, imag);
100            }
101        }
102
103        [SpecialName, PropertyMethod]
104        public static double Getreal(Complex self) {
105            return self.Real;
106        }
107
108        [SpecialName, PropertyMethod]
109        public static double Getimag(Complex self) {
110            return self.Imaginary();
111        }
112
113        #region Binary operators
114
115        [SpecialName]
116        public static Complex Add(Complex x, Complex y) {
117            return x + y;
118        }
119
120        [SpecialName]
121        public static Complex Subtract(Complex x, Complex y) {
122            return x - y;
123        }
124
125        [SpecialName]
126        public static Complex Multiply(Complex x, Complex y) {
127            return x * y;
128        }
129
130        [SpecialName]
131        public static Complex Divide(Complex x, Complex y) {
132            if (y.IsZero()) {
133                throw new DivideByZeroException("complex division by zero");
134            }
135
136            return x / y;
137        }
138
139        [SpecialName]
140        public static Complex TrueDivide(Complex x, Complex y) {
141            return Divide(x, y);
142        }
143
144        [SpecialName]
145        public static Complex op_Power(Complex x, Complex y) {
146            if (x.IsZero()) {
147                if (y.Real < 0.0 || y.Imaginary() != 0.0) {
148                    throw PythonOps.ZeroDivisionError("0.0 to a negative or complex power");
149                }
150                return y.IsZero() ? Complex.One : Complex.Zero;
151            }
152
153#if !CLR2
154            // Special case for higher precision with real integer powers
155            // TODO: A similar check may get added to CLR 4 upon resolution of Dev10 bug 863171,
156            // in which case this code should go away.
157            if (y.Imaginary == 0.0) {
158                int power = (int)y.Real;
159                if (power >= 0 && y.Real == power) {
160                    Complex res = Complex.One;
161                    if (power == 0) {
162                        return res;
163                    }
164                    Complex factor = x;
165                    while (power != 0) {
166                        if ((power & 1) != 0) {
167                            res = res * factor;
168                        }
169                        factor = factor * factor;
170                        power >>= 1;
171                    }
172                    return res;
173                }
174            }
175#endif
176
177            return x.Pow(y);
178        }
179
180        [PythonHidden]
181        public static Complex Power(Complex x, Complex y) {
182            return op_Power(x, y);
183        }
184
185        // floordiv for complex numbers is deprecated in the Python 2.
186        // specification; this function implements the observable
187        // functionality in CPython 2.4: 
188        //   Let x, y be complex.
189        //   Re(x//y) := floor(Re(x/y))
190        //   Im(x//y) := 0
191        [SpecialName]
192        public static Complex FloorDivide(CodeContext context, Complex x, Complex y) {
193            PythonOps.Warn(context, PythonExceptions.DeprecationWarning, "complex divmod(), // and % are deprecated");
194            Complex quotient = Divide(x, y);
195            return MathUtils.MakeReal(PythonOps.CheckMath(Math.Floor(quotient.Real)));
196        }
197
198        // mod for complex numbers is also deprecated. IronPython
199        // implements the CPython semantics, that is:
200        // x % y = x - (y * (x//y)).
201        [SpecialName]
202        public static Complex Mod(CodeContext context, Complex x, Complex y) {
203            Complex quotient = FloorDivide(context, x, y);
204            return x - (quotient * y);
205        }
206
207        [SpecialName]
208        public static PythonTuple DivMod(CodeContext context, Complex x, Complex y) {
209            Complex quotient = FloorDivide(context, x, y);
210            return PythonTuple.MakeTuple(quotient, x - (quotient * y));
211        }
212
213        #endregion
214
215        #region Unary operators
216
217        public static int __hash__(Complex x) {
218            if (x.Imaginary() == 0) {
219                return DoubleOps.__hash__(x.Real);
220            }
221            return x.GetHashCode();
222        }
223
224        public static bool __nonzero__(Complex x) {
225            return !x.IsZero();
226        }
227
228        public static Complex conjugate(Complex x) {
229            return x.Conjugate();
230        }
231
232        public static object __getnewargs__(CodeContext context, Complex self) {
233#if CLR2
234            if (!Object.ReferenceEquals(self, null)) {
235#endif
236                return PythonTuple.MakeTuple(
237                    PythonOps.GetBoundAttr(context, self, "real"),
238                    PythonOps.GetBoundAttr(context, self, "imag")
239                );
240#if CLR2
241            }
242            throw PythonOps.TypeErrorForBadInstance("__getnewargs__ requires a 'complex' object but received a '{0}'", self);
243#endif
244        }
245
246#if !CLR2
247        public static object __pos__(Complex x) {
248            return x;
249        }
250#endif
251
252        #endregion
253
254        public static object __coerce__(Complex x, object y) {
255            Complex right;
256            if (Converter.TryConvertToComplex(y, out right)) {
257#if !CLR2
258                if (double.IsInfinity(right.Real) && (y is BigInteger || y is Extensible<BigInteger>)) {
259                    throw new OverflowException("long int too large to convert to float");
260                }
261#endif
262                return PythonTuple.MakeTuple(x, right);
263            }
264
265            return NotImplementedType.Value;
266        }
267
268        public static string __str__(CodeContext/*!*/ context, Complex x) {
269            if (x.Real != 0) {
270                if (x.Imaginary() < 0 || DoubleOps.IsNegativeZero(x.Imaginary())) {
271                    return "(" + FormatComplexValue(context, x.Real) + FormatComplexValue(context, x.Imaginary()) + "j)";
272                } else /* x.Imaginary() is NaN or >= +0.0 */ {
273                    return "(" + FormatComplexValue(context, x.Real) + "+" + FormatComplexValue(context, x.Imaginary()) + "j)";
274                }
275            }
276
277            return FormatComplexValue(context, x.Imaginary()) + "j";
278        }
279
280        public static string __repr__(CodeContext/*!*/ context, Complex x) {
281            return __str__(context, x);
282        }
283
284        // report the same errors as CPython for these invalid conversions
285        public static double __float__(Complex self) {
286            throw PythonOps.TypeError("can't convert complex to float; use abs(z)");
287        }
288
289        public static int __int__(Complex self) {
290            throw PythonOps.TypeError(" can't convert complex to int; use int(abs(z))");
291        }
292
293        public static BigInteger __long__(Complex self) {
294            throw PythonOps.TypeError("can't convert complex to long; use long(abs(z))");
295        }
296
297        private static string FormatComplexValue(CodeContext/*!*/ context, double x) {
298            StringFormatter sf = new StringFormatter(context, "%.6g", x);
299            return sf.Format();
300        }
301        
302        // Unary Operations
303        [SpecialName]
304        public static double Abs(Complex x) {
305#if CLR2
306            double res = x.Abs();
307#else
308            // TODO: remove after CodePlex 26224 and MS internal 861649 are resolved
309            double res = MathUtils.Hypot(x.Real, x.Imaginary);
310#endif
311
312            if (double.IsInfinity(res) && !double.IsInfinity(x.Real) && !double.IsInfinity(x.Imaginary())) {
313                throw PythonOps.OverflowError("absolute value too large");
314            }
315
316            return res;
317        }
318
319        // Binary Operations - Comparisons (eq & ne defined on Complex type as operators)
320
321        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "y"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "x"), SpecialName]
322        public static bool LessThan(Complex x, Complex y) {
323            throw PythonOps.TypeError("complex is not an ordered type");
324        }
325        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "y"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "x"), SpecialName]
326        public static bool LessThanOrEqual(Complex x, Complex y) {
327            throw PythonOps.TypeError("complex is not an ordered type");
328        }
329        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "x"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "y"), SpecialName]
330        public static bool GreaterThan(Complex x, Complex y) {
331            throw PythonOps.TypeError("complex is not an ordered type");
332        }
333        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "y"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "x"), SpecialName]
334        public static bool GreaterThanOrEqual(Complex x, Complex y) {
335            throw PythonOps.TypeError("complex is not an ordered type");
336        }
337
338    }
339}