using System; // use number to index types (redo dynamic types myself) // 0 = integer // 1 = rational // 2 = real // 3 = complex public abstract class number { public bool equals(number x) { return numbers19.EQ[this.index(),x.index()](this,x); } public number add(number x) { return numbers19.AD[this.index(),x.index()](this,x); } public abstract int index(); }//abstract number public class integer : number { public int val; public integer(int v) {val=v;} public override string ToString() { return val+"";} public override int index() { return 0; } // like "bless" }//integer public class rational : number { public int n; //numerator and denominator public int d; public rational(int a, int b) { if (b!=0) { n=a; d=b;} else throw new Exception("bad rational"); } public override string ToString() { return n+"/"+d; } public override int index() { return 1; } } public class real : number // approximate real number { public double val; public real(double v) { val=v; } public override string ToString() { return val+""; } public override int index() { return 2; } } public class complex : number // complex number 2+3i (not used for now) { public double r; // real part public double i; // imaginary part public complex(double a, double b) {r=a; i=b; } public override string ToString() { return r+"+"+i+"i"; } public override int index() { return 3; } /* rules of complex arithmetic: (a+bi) + (c+di) = (a+c) + (b+d)i (a+bi) * (c+di) = (ac-bd)i + (bc+ad)i a+bi == c+di if a==c and b==d. A real r number can be cast to r+0i. */ }//complex /* Challenge: implement the .equals and .add methods without any use of if-else or switch statements. The .add method must keep the same level of precision. e.g., adding an integer to a rational should return a rational, not a real. rational(1/3) is more precise than 0.3333... You may add additional elements to the interface and classes. */ public class numbers19 { static bool eq(integer x, integer y) { return x.val==y.val; } static bool eq(integer x, rational y) { return x.val*y.d == y.n; } static bool eq(integer x, real y) { return x.val == y.val; } static bool eq(rational a, rational b) {return a.n*b.d==a.d*b.n;} static bool eq(rational a, real b) {return a.n/a.d == b.val; } static bool eq(real a, real b) { return a.val==b.val; } // ignore complex numbers for now... static number add(integer a,integer b) => new integer(a.val+b.val); static number add(rational a, rational b) {return new rational(a.n*b.d+b.n*a.d,a.d*b.d); } static number add(real a, real b)=> new real(a.val+b.val); static number add(integer a, rational b) => new rational(a.val*b.d+b.n,b.d); static number add(integer a, real b) => new real(a.val+b.val); static number add(rational a, real b) => new real(a.n*1.0/a.d+b.val); // this won't be enough. Why? // dispatch matrix for equality and addition public static Func[,] EQ; public static Func[,] AD; static void setdispatch() { EQ = new Func[4,4]; EQ[0,0] = (x,y)=>eq((integer)x,(integer)y); EQ[0,1] = (x,y)=>eq((integer)x,(rational)y); EQ[0,2] = (x,y)=>eq((integer)x,(real)y); EQ[1,1] = (x,y)=>eq((rational)x,(rational)y); EQ[1,2] = (x,y)=>eq((rational)x,(real)y); EQ[2,2] = (x,y)=>eq((real)x,(real)y); EQ[1,0] = (x,y)=>EQ[0,1](y,x); EQ[2,0] = (x,y)=>EQ[0,2](y,x); EQ[2,1] = (x,y)=>EQ[1,2](y,x); AD = new Func[4,4]; AD[0,0] = (x,y)=>add((integer)x,(integer)y); AD[0,1] = (x,y)=>add((integer)x,(rational)y); AD[0,2] = (x,y)=>add((integer)x,(real)y); AD[1,1] = (x,y)=>add((rational)x,(rational)y); AD[1,2] = (x,y)=>add((rational)x,(real)y); AD[2,2] = (x,y)=>add((real)x,(real)y); AD[1,0] = (x,y)=>AD[0,1](y,x); AD[2,0] = (x,y)=>AD[0,2](y,x); AD[2,1] = (x,y)=>AD[1,2](y,x); }// setdispatch // It's not just more code, it's loss of static type safety because of // all the type casting needed: what if AD[1,2] was assigned the wrong function? public static void Main() { setdispatch(); number[] N = {new rational(1,2),new integer(3),new real(3.14)}; number sum = new integer(0); // foreach(number x in N) sum = add(sum,x); // won't compile. why? foreach(number x in N) sum = sum.add(x); // uses AD matrix to dispatch Console.WriteLine(sum); }//main }//numbers19