Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit b6f9533

Browse files
morganbrkrwq
authored andcommitted
Numerics serialization (#20222)
Adds serialization support to BigInteger and Complex, which were inadvetently dropped in the previous cleanup. Also renames the private fields of Complex to match NetFX so that it will be serialization compatible.
1 parent 89ec132 commit b6f9533

File tree

2 files changed

+69
-66
lines changed

2 files changed

+69
-66
lines changed

src/System.Runtime.Numerics/src/System/Numerics/BigInteger.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
namespace System.Numerics
1010
{
11+
[Serializable]
1112
public struct BigInteger : IFormattable, IComparable, IComparable<BigInteger>, IEquatable<BigInteger>
1213
{
1314
private const int knMaskHighBit = int.MinValue;

src/System.Runtime.Numerics/src/System/Numerics/Complex.cs

Lines changed: 68 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ namespace System.Numerics
1212
/// A complex number z is a number of the form z = x + yi, where x and y
1313
/// are real numbers, and i is the imaginary unit, with the property i2= -1.
1414
/// </summary>
15+
[Serializable]
1516
public struct Complex : IEquatable<Complex>, IFormattable
1617
{
1718
public static readonly Complex Zero = new Complex(0.0, 0.0);
@@ -29,20 +30,21 @@ public struct Complex : IEquatable<Complex>, IFormattable
2930
// This value is used inside Asin and Acos.
3031
private static readonly double s_log2 = Math.Log(2.0);
3132

32-
private double _real;
33-
private double _imaginary;
33+
// Do not rename, these fields are needed for binary serialization
34+
private double m_real;
35+
private double m_imaginary;
3436

3537
public Complex(double real, double imaginary)
3638
{
37-
_real = real;
38-
_imaginary = imaginary;
39+
m_real = real;
40+
m_imaginary = imaginary;
3941
}
4042

41-
public double Real { get { return _real; } }
42-
public double Imaginary { get { return _imaginary; } }
43+
public double Real { get { return m_real; } }
44+
public double Imaginary { get { return m_imaginary; } }
4345

4446
public double Magnitude { get { return Abs(this); } }
45-
public double Phase { get { return Math.Atan2(_imaginary, _real); } }
47+
public double Phase { get { return Math.Atan2(m_imaginary, m_real); } }
4648

4749
public static Complex FromPolarCoordinates(double magnitude, double phase)
4850
{
@@ -76,34 +78,34 @@ public static Complex Divide(Complex dividend, Complex divisor)
7678

7779
public static Complex operator -(Complex value) /* Unary negation of a complex number */
7880
{
79-
return new Complex(-value._real, -value._imaginary);
81+
return new Complex(-value.m_real, -value.m_imaginary);
8082
}
8183

8284
public static Complex operator +(Complex left, Complex right)
8385
{
84-
return new Complex(left._real + right._real, left._imaginary + right._imaginary);
86+
return new Complex(left.m_real + right.m_real, left.m_imaginary + right.m_imaginary);
8587
}
8688

8789
public static Complex operator -(Complex left, Complex right)
8890
{
89-
return new Complex(left._real - right._real, left._imaginary - right._imaginary);
91+
return new Complex(left.m_real - right.m_real, left.m_imaginary - right.m_imaginary);
9092
}
9193

9294
public static Complex operator *(Complex left, Complex right)
9395
{
9496
// Multiplication: (a + bi)(c + di) = (ac -bd) + (bc + ad)i
95-
double result_Realpart = (left._real * right._real) - (left._imaginary * right._imaginary);
96-
double result_Imaginarypart = (left._imaginary * right._real) + (left._real * right._imaginary);
97-
return new Complex(result_Realpart, result_Imaginarypart);
97+
double result_realpart = (left.m_real * right.m_real) - (left.m_imaginary * right.m_imaginary);
98+
double result_imaginarypart = (left.m_imaginary * right.m_real) + (left.m_real * right.m_imaginary);
99+
return new Complex(result_realpart, result_imaginarypart);
98100
}
99101

100102
public static Complex operator /(Complex left, Complex right)
101103
{
102104
// Division : Smith's formula.
103-
double a = left._real;
104-
double b = left._imaginary;
105-
double c = right._real;
106-
double d = right._imaginary;
105+
double a = left.m_real;
106+
double b = left.m_imaginary;
107+
double c = right.m_real;
108+
double d = right.m_imaginary;
107109

108110
if (Math.Abs(d) < Math.Abs(c))
109111
{
@@ -119,7 +121,7 @@ public static Complex Divide(Complex dividend, Complex divisor)
119121

120122
public static double Abs(Complex value)
121123
{
122-
return Hypot(value._real, value._imaginary);
124+
return Hypot(value.m_real, value.m_imaginary);
123125
}
124126

125127
private static double Hypot(double a, double b)
@@ -191,13 +193,13 @@ private static double Log1P(double x)
191193
public static Complex Conjugate(Complex value)
192194
{
193195
// Conjugate of a Complex number: the conjugate of x+i*y is x-i*y
194-
return new Complex(value._real, -value._imaginary);
196+
return new Complex(value.m_real, -value.m_imaginary);
195197
}
196198

197199
public static Complex Reciprocal(Complex value)
198200
{
199201
// Reciprocal of a Complex number : the reciprocal of x+i*y is 1/(x+i*y)
200-
if (value._real == 0 && value._imaginary == 0)
202+
if (value.m_real == 0 && value.m_imaginary == 0)
201203
{
202204
return Zero;
203205
}
@@ -206,12 +208,12 @@ public static Complex Reciprocal(Complex value)
206208

207209
public static bool operator ==(Complex left, Complex right)
208210
{
209-
return left._real == right._real && left._imaginary == right._imaginary;
211+
return left.m_real == right.m_real && left.m_imaginary == right.m_imaginary;
210212
}
211213

212214
public static bool operator !=(Complex left, Complex right)
213215
{
214-
return left._real != right._real || left._imaginary != right._imaginary;
216+
return left.m_real != right.m_real || left.m_imaginary != right.m_imaginary;
215217
}
216218

217219
public override bool Equals(object obj)
@@ -222,47 +224,47 @@ public override bool Equals(object obj)
222224

223225
public bool Equals(Complex value)
224226
{
225-
return _real.Equals(value._real) && _imaginary.Equals(value._imaginary);
227+
return m_real.Equals(value.m_real) && m_imaginary.Equals(value.m_imaginary);
226228
}
227229

228230
public override int GetHashCode()
229231
{
230232
int n1 = 99999997;
231-
int realHash = _real.GetHashCode() % n1;
232-
int imaginaryHash = _imaginary.GetHashCode();
233+
int realHash = m_real.GetHashCode() % n1;
234+
int imaginaryHash = m_imaginary.GetHashCode();
233235
int finalHash = realHash ^ imaginaryHash;
234236
return finalHash;
235237
}
236238

237239
public override string ToString()
238240
{
239-
return string.Format(CultureInfo.CurrentCulture, "({0}, {1})", _real, _imaginary);
241+
return string.Format(CultureInfo.CurrentCulture, "({0}, {1})", m_real, m_imaginary);
240242
}
241243

242244
public string ToString(string format)
243245
{
244-
return string.Format(CultureInfo.CurrentCulture, "({0}, {1})", _real.ToString(format, CultureInfo.CurrentCulture), _imaginary.ToString(format, CultureInfo.CurrentCulture));
246+
return string.Format(CultureInfo.CurrentCulture, "({0}, {1})", m_real.ToString(format, CultureInfo.CurrentCulture), m_imaginary.ToString(format, CultureInfo.CurrentCulture));
245247
}
246248

247249
public string ToString(IFormatProvider provider)
248250
{
249-
return string.Format(provider, "({0}, {1})", _real, _imaginary);
251+
return string.Format(provider, "({0}, {1})", m_real, m_imaginary);
250252
}
251253

252254
public string ToString(string format, IFormatProvider provider)
253255
{
254-
return string.Format(provider, "({0}, {1})", _real.ToString(format, provider), _imaginary.ToString(format, provider));
256+
return string.Format(provider, "({0}, {1})", m_real.ToString(format, provider), m_imaginary.ToString(format, provider));
255257
}
256258

257259
public static Complex Sin(Complex value)
258260
{
259261
// We need both sinh and cosh of imaginary part. To avoid multiple calls to Math.Exp with the same value,
260262
// we compute them both here from a single call to Math.Exp.
261-
double p = Math.Exp(value._imaginary);
263+
double p = Math.Exp(value.m_imaginary);
262264
double q = 1.0 / p;
263265
double sinh = (p - q) * 0.5;
264266
double cosh = (p + q) * 0.5;
265-
return new Complex(Math.Sin(value._real) * cosh, Math.Cos(value._real) * sinh);
267+
return new Complex(Math.Sin(value.m_real) * cosh, Math.Cos(value.m_real) * sinh);
266268
// There is a known limitation with this algorithm: inputs that cause sinh and cosh to overflow, but for
267269
// which sin or cos are small enough that sin * cosh or cos * sinh are still representable, nonetheless
268270
// produce overflow. For example, Sin((0.01, 711.0)) should produce (~3.0E306, PositiveInfinity), but
@@ -273,8 +275,8 @@ public static Complex Sin(Complex value)
273275
public static Complex Sinh(Complex value)
274276
{
275277
// Use sinh(z) = -i sin(iz) to compute via sin(z).
276-
Complex sin = Sin(new Complex(-value._imaginary, value._real));
277-
return new Complex(sin._imaginary, -sin._real);
278+
Complex sin = Sin(new Complex(-value.m_imaginary, value.m_real));
279+
return new Complex(sin.m_imaginary, -sin.m_real);
278280
}
279281

280282
public static Complex Asin(Complex value)
@@ -299,18 +301,18 @@ public static Complex Asin(Complex value)
299301
}
300302

301303
public static Complex Cos(Complex value) {
302-
double p = Math.Exp(value._imaginary);
304+
double p = Math.Exp(value.m_imaginary);
303305
double q = 1.0 / p;
304306
double sinh = (p - q) * 0.5;
305307
double cosh = (p + q) * 0.5;
306-
return new Complex(Math.Cos(value._real) * cosh, -Math.Sin(value._real) * sinh);
308+
return new Complex(Math.Cos(value.m_real) * cosh, -Math.Sin(value.m_real) * sinh);
307309
}
308310

309311
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Cosh", Justification = "Cosh is the name of a mathematical function.")]
310312
public static Complex Cosh(Complex value)
311313
{
312314
// Use cosh(z) = cos(iz) to compute via cos(z).
313-
return Cos(new Complex(-value._imaginary, value._real));
315+
return Cos(new Complex(-value.m_imaginary, value.m_real));
314316
}
315317

316318
public static Complex Acos(Complex value)
@@ -345,12 +347,12 @@ public static Complex Tan(Complex value)
345347
// tan z = (sin(2x) / cosh(2y) + i \tanh(2y)) / (1 + cos(2x) / cosh(2y))
346348
// which correctly computes the (tiny) real part and the (normal-sized) imaginary part.
347349

348-
double x2 = 2.0 * value._real;
349-
double y2 = 2.0 * value._imaginary;
350+
double x2 = 2.0 * value.m_real;
351+
double y2 = 2.0 * value.m_imaginary;
350352
double p = Math.Exp(y2);
351353
double q = 1.0 / p;
352354
double cosh = (p + q) * 0.5;
353-
if (Math.Abs(value._imaginary) <= 4.0)
355+
if (Math.Abs(value.m_imaginary) <= 4.0)
354356
{
355357
double sinh = (p - q) * 0.5;
356358
double D = Math.Cos(x2) + cosh;
@@ -367,8 +369,8 @@ public static Complex Tan(Complex value)
367369
public static Complex Tanh(Complex value)
368370
{
369371
// Use tanh(z) = -i tan(iz) to compute via tan(z).
370-
Complex tan = Tan(new Complex(-value._imaginary, value._real));
371-
return new Complex(tan._imaginary, -tan._real);
372+
Complex tan = Tan(new Complex(-value.m_imaginary, value.m_real));
373+
return new Complex(tan.m_imaginary, -tan.m_real);
372374
}
373375

374376
public static Complex Atan(Complex value)
@@ -497,7 +499,7 @@ private static void Asin_Internal (double x, double y, out double b, out double
497499

498500
public static Complex Log(Complex value)
499501
{
500-
return new Complex(Math.Log(Abs(value)), Math.Atan2(value._imaginary, value._real));
502+
return new Complex(Math.Log(Abs(value)), Math.Atan2(value.m_imaginary, value.m_real));
501503
}
502504

503505
public static Complex Log(Complex value, double baseValue)
@@ -513,26 +515,26 @@ public static Complex Log10(Complex value)
513515

514516
public static Complex Exp(Complex value)
515517
{
516-
double expReal = Math.Exp(value._real);
517-
double cosImaginary = expReal * Math.Cos(value._imaginary);
518-
double sinImaginary = expReal * Math.Sin(value._imaginary);
518+
double expReal = Math.Exp(value.m_real);
519+
double cosImaginary = expReal * Math.Cos(value.m_imaginary);
520+
double sinImaginary = expReal * Math.Sin(value.m_imaginary);
519521
return new Complex(cosImaginary, sinImaginary);
520522
}
521523

522524
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Sqrt", Justification = "Sqrt is the name of a mathematical function.")]
523525
public static Complex Sqrt(Complex value)
524526
{
525527

526-
if (value._imaginary == 0.0)
528+
if (value.m_imaginary == 0.0)
527529
{
528530
// Handle the trivial case quickly.
529-
if (value._real < 0.0)
531+
if (value.m_real < 0.0)
530532
{
531-
return new Complex(0.0, Math.Sqrt(-value._real));
533+
return new Complex(0.0, Math.Sqrt(-value.m_real));
532534
}
533535
else
534536
{
535-
return new Complex(Math.Sqrt(value._real), 0.0);
537+
return new Complex(Math.Sqrt(value.m_real), 0.0);
536538
}
537539
}
538540
else
@@ -565,35 +567,35 @@ public static Complex Sqrt(Complex value)
565567
// make the result representable. To avoid this, we re-scale (by exact powers of 2 for accuracy)
566568
// when we encounter very large components to avoid intermediate infinities.
567569
bool rescale = false;
568-
if ((Math.Abs(value._real) >= s_sqrtRescaleThreshold) || (Math.Abs(value._imaginary) >= s_sqrtRescaleThreshold))
570+
if ((Math.Abs(value.m_real) >= s_sqrtRescaleThreshold) || (Math.Abs(value.m_imaginary) >= s_sqrtRescaleThreshold))
569571
{
570-
if (double.IsInfinity(value._imaginary) && !double.IsNaN(value._real))
572+
if (double.IsInfinity(value.m_imaginary) && !double.IsNaN(value.m_real))
571573
{
572574
// We need to handle infinite imaginary parts specially because otherwise
573575
// our formulas below produce inf/inf = NaN. The NaN test is necessary
574576
// so that we return NaN rather than (+inf,inf) for (NaN,inf).
575-
return (new Complex(double.PositiveInfinity, value._imaginary));
577+
return (new Complex(double.PositiveInfinity, value.m_imaginary));
576578
}
577579
else
578580
{
579-
value._real *= 0.25;
580-
value._imaginary *= 0.25;
581+
value.m_real *= 0.25;
582+
value.m_imaginary *= 0.25;
581583
rescale = true;
582584
}
583585
}
584586

585587
// This is the core of the algorithm. Everything else is special case handling.
586588
double x, y;
587-
if (value._real >= 0.0)
589+
if (value.m_real >= 0.0)
588590
{
589-
x = Math.Sqrt((Hypot(value._real, value._imaginary) + value._real) * 0.5);
590-
y = value._imaginary / (2.0 * x);
591+
x = Math.Sqrt((Hypot(value.m_real, value.m_imaginary) + value.m_real) * 0.5);
592+
y = value.m_imaginary / (2.0 * x);
591593
}
592594
else
593595
{
594-
y = Math.Sqrt((Hypot(value._real, value._imaginary) - value._real) * 0.5);
595-
if (value._imaginary < 0.0) y = -y;
596-
x = value._imaginary / (2.0 * y);
596+
y = Math.Sqrt((Hypot(value.m_real, value.m_imaginary) - value.m_real) * 0.5);
597+
if (value.m_imaginary < 0.0) y = -y;
598+
x = value.m_imaginary / (2.0 * y);
597599
}
598600

599601
if (rescale)
@@ -620,10 +622,10 @@ public static Complex Pow(Complex value, Complex power)
620622
return Zero;
621623
}
622624

623-
double valueReal = value._real;
624-
double valueImaginary = value._imaginary;
625-
double powerReal = power._real;
626-
double powerImaginary = power._imaginary;
625+
double valueReal = value.m_real;
626+
double valueImaginary = value.m_imaginary;
627+
double powerReal = power.m_real;
628+
double powerImaginary = power.m_imaginary;
627629

628630
double rho = Abs(value);
629631
double theta = Math.Atan2(valueImaginary, valueReal);
@@ -641,8 +643,8 @@ public static Complex Pow(Complex value, double power)
641643

642644
private static Complex Scale(Complex value, double factor)
643645
{
644-
double realResult = factor * value._real;
645-
double imaginaryResuilt = factor * value._imaginary;
646+
double realResult = factor * value.m_real;
647+
double imaginaryResuilt = factor * value.m_imaginary;
646648
return new Complex(realResult, imaginaryResuilt);
647649
}
648650

0 commit comments

Comments
 (0)