/* Push OOP to Its Limits Hofstra student Haten Umbers wants to conquer his fear of numbers by writing a program in C# that can process four types of numbers: integer, rational, real and complex. He's been given the following definition of what these numbers are: they all have abstract type "number". He needs to write a program that can compare any pair of numbers for equality ( for example, rational 1/4 is equal to real 0.25), as well as a function that can add any two numbers without losing precision (integer 2 plus rational 1/3 is rational 7/3). Help Mr. Umbers write this program or he'll hate you as well ... */ using System; public abstract class number { public abstract number negate(); public abstract number upcast(); public abstract number downcast(); public abstract T match( Func I, // Func means integer -> T Func F, Func R, Func C); public override String ToString() { return this.match( I: n => ""+n.val, F: n => n.n+"/"+n.d, R: n => ""+n.val, C: n => n.r+"+"+n.i+"i" ); } }// abstract class number; public class integer : number { public int val; public integer(int x) {this.val=x;} public override number negate() { return new integer(-1*val); } public override number upcast() => new rational(val,1); // same as return.. public override number downcast() => this; public override T match( Func I, Func F, Func R, Func C) => I(this); }//integer public class rational : number { public int n; //numerator public int d=1; //denominator public rational(int n, int d) { this.n=n; if (d!=0) this.d = d; else Console.Error.WriteLine("warning: zero denominator avoided"); } public override number negate() { return new rational(-1*n,d); } public override number upcast() { return this; } //can't lose precision public override number downcast() { if (n%d==0) return new integer(n/d); else return this; } public override T match( Func I, Func F, Func R, Func C) => F(this); }//rational public class real : number { public double val; public real(double r) {val=r;} public override number negate() { return new real(-1*val); } public override number upcast() { return new complex(val,0.0);} public override number downcast() { return this; } //would lose precision public override T match( Func I, Func F, Func R, Func C) => R(this); }//real public class complex : number { public double r; // real part public double i; // imaginary part public complex(double a, double b) {r=a; i=b;} public override number negate() { return new complex(-1*r,-1*i); } public override number upcast() { return this; } public override number downcast() { if (i==0) return new real(r); else return this; } public override T match( Func I, Func F, Func R, Func C) => C(this); }//complex /* rules of rational arithmetic: a/b + c/d = (a*d+c*b)/b*d a/b * c/d = (a*c)/(b*d) a/b==c/d if a*d==b*c an integer n can be cast to a rational as n/1 a rational should not be cast to a real as that will cause a loss of precision: only convert when adding rational to real/complex. rules of complex arithmetic: (a+bi) + (c+di) = (a+c) + (b+d)i (a+bi) * (c+di) = (ac-bd) + (bc+ad)i a+bi == c+di if a==c and b==d. Complex inequalities don't exit. (So -1+0i * c+di = -c + -1*i = -c-i) The multiplicative inverse of a+bi is a/s -(b/s)i where s = a*a + b*b, assuming not both a and b are zero. A real number r can be cast to complex r+0i and similarly with rationals and integers. */ public class numbers { //Write a function // static boolean equals(number a, number b) // That compares any two numers for equality. For example, a rational(4,2) // is equals to an integer(2). // The following approach WILL NOT WORK. Why? static bool equals(integer a, integer b) { return a.val==b.val; } static bool equals(integer a, rational b) => a.val*b.d == b.n; static bool equals(rational a, rational b) => a.n*b.d == a.d*b.n; static bool equals(rational a, real b) => a.n*1.0 == a.d*b.val; static bool equals(rational a, integer b) => equals(b,a); //one-time recursion // .. you can do all the cases but it still won't work. //Write a function // static number add(number a, number b) //that returns the sum of any two numbers WITHOUT LOSING PRECISION. //For example, the sum of two rationals should be a rational, not a real. public static void Main() { // test stuff here number h1 = new rational(1,2); number r1 = new real(0.5); number i1 = new integer(-1); number c1 = new complex(0.3,2); //Console.WriteLine(equals(h1,r1)); //Console.WriteLine(equals(h1,new complex(0.5,0))); number[] NUMS = {h1,r1,i1,c1}; number sum = new integer(0); foreach(var n in NUMS) { Console.WriteLine(n); //sum = add(n,sum); } //Console.WriteLine("sum : "+ sum); }//main }