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