1 using System;
2 using System.Collections;
3 using System.Concepts;
4 using System.Numerics.Multiprecision;
5
6 namespace BigNumCalc
7 {
8 public concept BigValueType<T>
9 {
10 where Derived<T, BigValue>;
11 }
12
13 public class EvaluationStack
14 {
15 public void Push(BigValue* value)
16 {
17 stack.Push(UniquePtr<BigValue>(value));
18 }
19 public BigValue* Pop()
20 {
21 UniquePtr<BigValue> value = stack.Pop();
22 return value.Release();
23 }
24 private Stack<UniquePtr<BigValue>> stack;
25 }
26
27 public BigValue* UnaryEvaluate<BigValueT, Op>(BigValue* operand, Op op) where BigValueT is BigValueType and Op is UnaryFunction
28 {
29 BigValueT* value = cast<BigValueT*>(operand);
30 BigValueT.OperandType result = op(value->Get());
31 return new BigValueT(result);
32 }
33
34 public inline BigValue* UnaryPlus<BigValueT>(BigValue* operand) where BigValueT is BigValueType
35 {
36 return UnaryEvaluate<BigValueT>(operand, Identity<BigValueT.OperandType>());
37 }
38
39 public inline BigValue* UnaryMinus<BigValueT>(BigValue* operand) where BigValueT is BigValueType
40 {
41 return UnaryEvaluate<BigValueT>(operand, Negate<BigValueT.OperandType>());
42 }
43
44 public delegate BigValue* UnaryOperatorDelegate(BigValue* operand);
45
46 public nothrow UnaryOperatorDelegate GetUnaryOperatorDelegate(uchar op, BigNumKind kind)
47 {
48 UnaryOperatorDelegate dlg;
49 switch (op)
50 {
51 case '+':
52 {
53 switch (kind)
54 {
55 case BigNumKind.bigInt: dlg = UnaryPlus<BigIntValue>; break;
56 case BigNumKind.bigRational: dlg = UnaryPlus<BigRationalValue>; break;
57 case BigNumKind.bigFloat: dlg = UnaryPlus<BigFloatValue>; break;
58 }
59 break;
60 }
61 case '-':
62 {
63 switch (kind)
64 {
65 case BigNumKind.bigInt: dlg = UnaryMinus<BigIntValue>; break;
66 case BigNumKind.bigRational: dlg = UnaryMinus<BigRationalValue>; break;
67 case BigNumKind.bigFloat: dlg = UnaryMinus<BigFloatValue>; break;
68 }
69 break;
70 }
71 }
72 return dlg;
73 }
74
75 public BigValue* Evaluate(BigValue* operand, uchar op)
76 {
77 UnaryOperatorDelegate dlg = GetUnaryOperatorDelegate(op, operand->Kind());
78 if (dlg != UnaryOperatorDelegate())
79 {
80 BigValue* result = dlg(operand);
81 if (result != null)
82 {
83 return result;
84 }
85 else
86 {
87 throw Exception("operator '" + ToUtf8(CharStr(op)) + "' not implemented for this operand type");
88 }
89 }
90 else
91 {
92 throw Exception("operator '" + ToUtf8(CharStr(op)) + "' not implemented");
93 }
94 }
95
96 public BigValue* BinaryEvaluate<BigValueT, Op>(BigValue* left, BigValue* right, Op op) where BigValueT is BigValueType and Op is BinaryFunction
97 {
98 BigValueT* left_ = cast<BigValueT*>(left);
99 BigValueT* right_ = cast<BigValueT*>(right);
100 BigValueT.OperandType result = op(left_->Get(), right_->Get());
101 return new BigValueT(result);
102 }
103
104 public inline BigValue* Add<BigValueT>(BigValue* left, BigValue* right) where BigValueT is BigValueType
105 {
106 return BinaryEvaluate<BigValueT>(left, right, Plus<BigValueT.OperandType>());
107 }
108
109 public inline BigValue* Sub<BigValueT>(BigValue* left, BigValue* right) where BigValueT is BigValueType
110 {
111 return BinaryEvaluate<BigValueT>(left, right, Minus<BigValueT.OperandType>());
112 }
113
114 public inline BigValue* Mul<BigValueT>(BigValue* left, BigValue* right) where BigValueT is BigValueType
115 {
116 return BinaryEvaluate<BigValueT>(left, right, Multiplies<BigValueT.OperandType>());
117 }
118
119 public inline BigValue* Div<BigValueT>(BigValue* left, BigValue* right) where BigValueT is BigValueType
120 {
121 return BinaryEvaluate<BigValueT>(left, right, Divides<BigValueT.OperandType>());
122 }
123
124 public delegate BigValue* BinaryOperatorDelegate(BigValue* left, BigValue* right);
125
126 public nothrow BinaryOperatorDelegate GetBinaryOperatorDelegate(uchar op, BigNumKind kind)
127 {
128 BinaryOperatorDelegate dlg;
129 switch (op)
130 {
131 case '+':
132 {
133 switch (kind)
134 {
135 case BigNumKind.bigInt: dlg = Add<BigIntValue>; break;
136 case BigNumKind.bigRational: dlg = Add<BigRationalValue>; break;
137 case BigNumKind.bigFloat: dlg = Add<BigFloatValue>; break;
138 }
139 break;
140 }
141 case '-':
142 {
143 switch (kind)
144 {
145 case BigNumKind.bigInt: dlg = Sub<BigIntValue>; break;
146 case BigNumKind.bigRational: dlg = Sub<BigRationalValue>; break;
147 case BigNumKind.bigFloat: dlg = Sub<BigFloatValue>; break;
148 }
149 break;
150 }
151 case '*':
152 {
153 switch (kind)
154 {
155 case BigNumKind.bigInt: dlg = Mul<BigIntValue>; break;
156 case BigNumKind.bigRational: dlg = Mul<BigRationalValue>; break;
157 case BigNumKind.bigFloat: dlg = Mul<BigFloatValue>; break;
158 }
159 break;
160 }
161 case '/':
162 {
163 switch (kind)
164 {
165 case BigNumKind.bigInt: dlg = Div<BigIntValue>; break;
166 case BigNumKind.bigRational: dlg = Div<BigRationalValue>; break;
167 case BigNumKind.bigFloat: dlg = Div<BigFloatValue>; break;
168 }
169 break;
170 }
171 }
172 return dlg;
173 }
174
175 public BigValue* Evaluate(BigValue* left, BigValue* right, uchar op)
176 {
177 BigNumKind commonType = CommonType(left->Kind(), right->Kind());
178 UniquePtr<BigValue> left_(left->As(commonType));
179 UniquePtr<BigValue> right_(right->As(commonType));
180 BinaryOperatorDelegate dlg = GetBinaryOperatorDelegate(op, commonType);
181 if (dlg != BinaryOperatorDelegate())
182 {
183 BigValue* result = dlg(left_.Get(), right_.Get());
184 if (result != null)
185 {
186 return result;
187 }
188 else
189 {
190 throw Exception("operator '" + ToUtf8(CharStr(op)) + "' not implemented for these operand types");
191 }
192 }
193 else
194 {
195 throw Exception("operator '" + ToUtf8(CharStr(op)) + "' not implemented");
196 }
197 }
198 }