Skip to content

Commit 5cd8c11

Browse files
author
Rick Button
committed
Eliminated double implementation of complex numbers
1 parent bc6732c commit 5cd8c11

13 files changed

Lines changed: 123 additions & 423 deletions

File tree

src/Scheme.NET.Tests/NumberTests/NumberTests.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,24 +25,24 @@ private void TestPromote(Complex a, bool ab, bool aa, Complex b, bool bb, bool b
2525
[Test]
2626
public void TestPromoteE()
2727
{
28-
Complex a = Complex.FromInteger(1);
29-
Complex b = Complex.FromInteger(1);
28+
Complex a = Complex.CreateExactReal(1);
29+
Complex b = Complex.CreateExactReal(1);
3030
TestPromote(a, true, true, b, true, true);
3131
}
3232

3333
[Test]
3434
public void TestPromoteI()
3535
{
36-
Complex a = Complex.FromDouble(1);
37-
Complex b = Complex.FromDouble(1);
36+
Complex a = Complex.CreateInexactReal(1);
37+
Complex b = Complex.CreateInexactReal(1);
3838
TestPromote(a, false, false, b, false, false);
3939
}
4040

4141
[Test]
4242
public void TestPromoteEI()
4343
{
44-
Complex a = Complex.FromInteger(1);
45-
Complex b = Complex.FromDouble(1.0);
44+
Complex a = Complex.CreateExactReal(1);
45+
Complex b = Complex.CreateInexactReal(1.0);
4646

4747
TestPromote(a, true, false, b, false, false);
4848
TestPromote(b, false, false, a, true, false);
@@ -55,8 +55,8 @@ public void TestPromoteEILinq()
5555

5656
var complexes = ints
5757
.Select(i => i == 1 ?
58-
(Complex)Complex.FromInteger(i) :
59-
(Complex)Complex.FromDouble(i)).ToList();
58+
(Complex)Complex.CreateExactReal(i) :
59+
(Complex)Complex.CreateInexactReal(i)).ToList();
6060

6161
Assert.AreEqual(2, complexes.Count(c => !c.IsExact));
6262
complexes = complexes.Select(c => c.PromoteRelative(complexes)).ToList();

src/Scheme.NET.Tests/Scheme.NET.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
<HintPath>..\..\packages\NUnit.3.7.1\lib\net45\nunit.framework.dll</HintPath>
4242
<Private>True</Private>
4343
</Reference>
44+
<Reference Include="Rationals, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
4445
<Reference Include="System" />
4546
<Reference Include="System.Core" />
4647
<Reference Include="System.Numerics" />

src/Scheme.NET/Lib/Arithmetic.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public static ISExpression Div(Scope scope, IEnumerable<ISExpression> args)
4444
LibHelper.EnsureMinArgCount(args, 1);
4545

4646
if (args.Count() == 1)
47-
return AtomHelper.NumberFromComplex(Complex.FromInteger(1) / (args.First() as NumberAtom).Val);
47+
return AtomHelper.NumberFromComplex(Complex.CreateExactReal(1) / (args.First() as NumberAtom).Val);
4848

4949
var v = (args.First() as NumberAtom).Val;
5050

@@ -65,14 +65,14 @@ public static ISExpression Positive(Scope scope, IEnumerable<ISExpression> args)
6565
{
6666
LibHelper.EnsureAllReal(args);
6767
LibHelper.EnsureArgCount(args, 1);
68-
return AtomHelper.BooleanFromBool(args.Cast<NumberAtom>().First().Val.Real.IsPositive);
68+
return AtomHelper.BooleanFromBool(args.Cast<NumberAtom>().First().Val.Real.IsPositive());
6969
}
7070

7171
public static ISExpression Negative(Scope scope, IEnumerable<ISExpression> args)
7272
{
7373
LibHelper.EnsureAllReal(args);
7474
LibHelper.EnsureArgCount(args, 1);
75-
return AtomHelper.BooleanFromBool(args.Cast<NumberAtom>().First().Val.Real.IsNegative);
75+
return AtomHelper.BooleanFromBool(args.Cast<NumberAtom>().First().Val.Real.IsNegative());
7676
}
7777

7878
public static ISExpression Odd(Scope scope, IEnumerable<ISExpression> args)
@@ -82,7 +82,7 @@ public static ISExpression Odd(Scope scope, IEnumerable<ISExpression> args)
8282

8383
var n = args.Cast<NumberAtom>().First().Val.Real;
8484

85-
return AtomHelper.BooleanFromBool(n.IsOdd);
85+
return AtomHelper.BooleanFromBool(n.IsOdd());
8686
}
8787

8888
public static ISExpression Even(Scope scope, IEnumerable<ISExpression> args)
@@ -92,7 +92,7 @@ public static ISExpression Even(Scope scope, IEnumerable<ISExpression> args)
9292

9393
var n = args.Cast<NumberAtom>().First().Val.Real;
9494

95-
return AtomHelper.BooleanFromBool(n.IsEven || n.IsZero);
95+
return AtomHelper.BooleanFromBool(n.IsEven() || n.IsZero);
9696
}
9797

9898
public static ISExpression Min(Scope scope, IEnumerable<ISExpression> args)
@@ -129,7 +129,7 @@ public static ISExpression Quotient(Scope scope, IEnumerable<ISExpression> args)
129129

130130
var c = a.Val / b.Val;
131131

132-
if (c.Real.IsInteger)
132+
if (c.Real.IsInteger())
133133
{
134134
return AtomHelper.NumberFromComplex(c);
135135
}
@@ -226,7 +226,7 @@ private static Complex LCM(Complex[] numbers)
226226

227227
private static NumberAtom Sum(this IEnumerable<NumberAtom> ee)
228228
{
229-
Complex sum = Complex.FromInteger(0);
229+
Complex sum = Complex.CreateExactReal(0);
230230
foreach (var e in ee)
231231
sum = sum + e.Val;
232232

@@ -235,7 +235,7 @@ private static NumberAtom Sum(this IEnumerable<NumberAtom> ee)
235235

236236
private static NumberAtom Multiply(this IEnumerable<NumberAtom> ee)
237237
{
238-
Complex m = Complex.FromInteger(1);
238+
Complex m = Complex.CreateExactReal(1);
239239
foreach (var e in ee)
240240
m = m * e.Val;
241241

src/Scheme.NET/Lib/Convert.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public static ISExpression NumberToString(Scope scope, IEnumerable<ISExpression>
2222
if (args.Count() > 1)
2323
{
2424
var radixArg = (NumberAtom)args.ToArray()[1];
25-
radix = (int)((double)radixArg.Val.ExactToInexact().Real.BackingValue);
25+
radix = (int)radixArg.Val.Real;
2626
}
2727

2828
if (!ValidRadix.Contains(radix))

src/Scheme.NET/Numbers/Complex.cs

Lines changed: 33 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -10,55 +10,50 @@ namespace Scheme.NET.Numbers
1010
{
1111
public class Complex : IComparable<Complex>, IEquatable<Complex>
1212
{
13-
public IComplexPart Real { get; }
14-
public IComplexPart Imag { get; }
13+
public Rational Real { get; }
14+
public Rational Imag { get; }
1515
public bool IsExact { get; private set; }
1616

1717
public bool IsZero => Real.IsZero && Imag.IsZero;
18-
public bool IsInteger => Real.IsInteger && Imag.IsInteger;
18+
public bool IsInteger => Real.IsInteger() && Imag.IsInteger();
1919

20-
private Complex(IComplexPart real, IComplexPart imag, bool isExact)
20+
public Complex(Rational real, Rational imag, bool isExact)
2121
{
2222
Real = real;
2323
Imag = imag;
2424
IsExact = isExact;
2525
}
2626

27-
public Complex(RationalPart real, RationalPart imag)
28-
{
29-
Real = real;
30-
Imag = imag;
31-
IsExact = true;
32-
}
33-
34-
public Complex(DoublePart real, DoublePart imag)
35-
{
36-
Real = real;
37-
Imag = imag;
38-
IsExact = false;
39-
}
40-
41-
public static Complex operator +(Complex a, Complex b) { return DoBinary(a, b, (x, y) => x.Add(y)); }
42-
public static Complex operator -(Complex a, Complex b) { return DoBinary(a, b, (x, y) => x.Sub(y)); }
43-
public static Complex operator -(Complex a) { return DoUnary(a, (x) => x.Negate()); }
27+
public static Complex operator +(Complex a, Complex b) { return DoBinary(a, b, (x, y) => x + y); }
28+
public static Complex operator -(Complex a, Complex b) { return DoBinary(a, b, (x, y) => x - y); }
29+
public static Complex operator -(Complex a) { return DoUnary(a, (x) => -x); }
4430
public static Complex operator *(Complex x, Complex y) {
4531
PromoteExactness(x, y, out x, out y);
46-
var newReal = x.Real.Mul(y.Real).Sub(y.Imag.Mul(y.Imag));
47-
var newImag = x.Real.Mul(y.Imag).Add(x.Imag.Mul(y.Real));
32+
var newReal = (x.Real * y.Real) - (y.Imag * y.Imag);
33+
var newImag = (x.Real * y.Imag) + (x.Imag * y.Real);
4834
return new Complex(newReal, newImag, x.IsExact);
4935
}
5036
public static Complex operator /(Complex x, Complex y) {
5137
PromoteExactness(x, y, out x, out y);
52-
IComplexPart divisor = y.Real.Mul(y.Real).Add(y.Imag.Mul(y.Imag));
53-
var newReal = x.Real.Mul(y.Real).Add(x.Imag.Mul(y.Imag)).Div(divisor);
54-
var newImag = x.Imag.Mul(y.Real).Sub(x.Real.Mul(y.Imag)).Div(divisor);
38+
Rational divisor = (y.Real * y.Real) + (y.Imag * y.Imag);
39+
var newReal = ((x.Real * y.Real) + (x.Imag * y.Imag)) / divisor;
40+
var newImag = ((x.Imag * y.Real) - (x.Real * y.Imag)) / divisor;
5541
return new Complex(newReal, newImag, x.IsExact);
5642
}
5743

5844
public string ToString(int radix)
5945
{
60-
string real = Real.ToString(radix);
61-
string imag = Imag.ToString(radix, true);
46+
string real, imag;
47+
if (IsExact)
48+
{
49+
real = Real.ToString(radix);
50+
imag = Imag.ToString(radix, true);
51+
}
52+
else
53+
{
54+
real = Real.ToDecimalString(radix);
55+
imag = Imag.ToDecimalString(radix, true);
56+
}
6257

6358
if (!Imag.IsZero)
6459
{
@@ -86,26 +81,26 @@ public Complex RealAbs()
8681
public Complex RealGCD(Complex b) { return DoRealBinary(this, b, (x, y) => x.GCD(y)); }
8782
public Complex RealModulo(Complex b) { return DoRealBinary(this, b, (x, y) => x.Modulo(y)); }
8883

89-
private static Complex DoRealUnary(Complex a, Func<IComplexPart, IComplexPart> func)
84+
private static Complex DoRealUnary(Complex a, Func<Rational, Rational> func)
9085
{
9186
if (!a.Imag.IsZero)
9287
throw new InvalidOperationException();
9388
return new Complex(func(a.Real), a.Imag, a.IsExact);
9489
}
9590

96-
private static Complex DoRealBinary(Complex a, Complex b, Func<IComplexPart, IComplexPart, IComplexPart> func)
91+
private static Complex DoRealBinary(Complex a, Complex b, Func<Rational, Rational, Rational> func)
9792
{
9893
if (!a.Imag.IsZero)
9994
throw new InvalidOperationException();
100-
return new Complex(func(a.Real, b.Real), RationalPart.FromInteger(0), a.IsExact);
95+
return new Complex(func(a.Real, b.Real), 0, a.IsExact);
10196
}
10297

103-
private static Complex DoUnary(Complex a, Func<IComplexPart, IComplexPart> func)
98+
private static Complex DoUnary(Complex a, Func<Rational, Rational> func)
10499
{
105100
return new Complex(func(a.Real), func(a.Imag), a.IsExact);
106101
}
107102

108-
private static Complex DoBinary(Complex a, Complex b, Func<IComplexPart, IComplexPart, IComplexPart> func)
103+
private static Complex DoBinary(Complex a, Complex b, Func<Rational, Rational, Rational> func)
109104
{
110105
PromoteExactness(a, b, out a, out b);
111106
return new Complex(func(a.Real, b.Real), func(a.Imag, b.Imag), a.IsExact);
@@ -164,33 +159,13 @@ public Complex ExactToInexact()
164159
if (!this.IsExact)
165160
throw new InvalidOperationException();
166161

167-
var real = this.Real as RationalPart;
168-
var imag = this.Imag as RationalPart;
169-
170-
return new Complex(
171-
new DoublePart((double)real.Rational),
172-
new DoublePart((double)imag.Rational));
162+
return new Complex(Real, Imag, false);
173163
}
174164

175-
public static Complex FromRationals(Rational a, Rational b)
176-
{
177-
return new Complex(RationalPart.FromRational(a), RationalPart.FromRational(b));
178-
}
179-
180-
public static Complex FromDoubles(double a, double b)
181-
{
182-
return new Complex(DoublePart.FromDouble(a), DoublePart.FromDouble(b));
183-
}
184-
185-
public static Complex FromInteger(BigInteger i)
186-
{
187-
return new Complex(RationalPart.FromInteger(i), RationalPart.FromInteger(0));
188-
}
189-
190-
public static Complex FromDouble(double d)
191-
{
192-
return new Complex(DoublePart.FromDouble(d), DoublePart.FromDouble(0));
193-
}
165+
public static Complex CreateExactReal(Rational a) { return new Complex(a, 0, true); }
166+
public static Complex CreateExact(Rational a, Rational b) { return new Complex(a, b, true); }
167+
public static Complex CreateInexactReal(double a) { return new Complex((Rational)a, 0, false); }
168+
public static Complex CreateInExact(Rational a, Rational b) { return new Complex(a, b, false); }
194169

195170
public override int GetHashCode()
196171
{

0 commit comments

Comments
 (0)