1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215:
216:
217:
218:
219:
220:
221:
222:
223:
224:
225:
226:
227:
228:
229:
230:
231:
232:
233:
234:
235:
236:
237:
238:
239:
240:
241:
242:
243:
244:
245:
246:
247:
248:
249:
250:
251:
252:
253:
254:
255:
256:
257:
258:
259:
260:
261:
262:
263:
264:
265:
266:
267:
268:
269:
270:
271:
272:
273:
274:
275:
276:
277:
278:
279:
280:
281:
282:
283:
284:
285:
286:
287:
288:
289:
290:
291:
292:
293:
294:
295:
296:
297:
298:
299:
300:
301:
302:
303:
304:
305:
306:
307:
308:
309:
310:
311:
312:
313:
314:
315:
316:
317:
318:
319:
320:
321:
322:
323:
324:
325:
326:
327:
328:
329:
330:
331:
332:
333:
334:
335:
336:
337:
338:
339:
340:
341:
342:
343:
344:
345:
346:
347:
348:
|
public class Differenzierer : Parser
{
public static string Ableiten(string nach, Parser abzuleiten)
{
string erg = AbleitenRek(nach, abzuleiten.wurzel);
string tmp = "";
while (tmp != erg)
{
tmp = erg;
Parser p = new Parser(erg);
p.Simplify();
erg = p.ToString();
}
return erg;
}
private static string AbleitenRek(string nach, Knoten k)
{
if (k.rechts == null && k.links == null) //nur noch Konstante
{
if (k.op == nach) return "1";
return "0";
}
if (k.links == null) //z.B. sin(x)
{
switch (k.op)
{
case "-": return "(-(" + AbleitenRek(nach, k.rechts) + "))";
case "sin": return "(cos(" + k.rechts.ToString() + ")*(" + AbleitenRek(nach, k.rechts) + "))";
case "cos": return "(-sin(" + k.rechts.ToString() + ")*(" + AbleitenRek(nach, k.rechts) + "))";
case "tan": return "(1/cos(" + k.rechts.ToString() + ")^2*(" + AbleitenRek(nach, k.rechts) + "))";
case "ln": return "(1/(" + k.rechts.ToString() + ")*(" + AbleitenRek(nach, k.rechts) + "))";
case "lg": return "(1/(ln(10)*(" + k.rechts.ToString() + ")*(" + AbleitenRek(nach, k.rechts) + ")))";
case "log": return "(1/(ln(" + k.rechts.links + ")*(" + k.rechts.rechts.ToString() + ")*(" + AbleitenRek(nach, k.rechts.rechts) + ")))";
case "abs": return "((" + k.rechts.ToString() + ")/abs(" + k.rechts.ToString() + ")*(" + AbleitenRek(nach, k.rechts) + "))";
}
}
switch (k.op)
{
case "+": return "((" + AbleitenRek(nach, k.links) + ")+(" + AbleitenRek(nach, k.rechts) + "))";
case "-": return "((" + AbleitenRek(nach, k.links) + ")-(" + AbleitenRek(nach, k.rechts) + "))";
case "*": return "(" + AbleitenRek(nach, k.links) + ")*(" + k.rechts.ToString() + ")+(" + k.links.ToString() + ")*(" + AbleitenRek(nach, k.rechts) + ")";
case "/": return "((" + k.rechts.ToString() + ")*(" + AbleitenRek(nach, k.links) + ")-(" + k.links.ToString() + ")*(" + AbleitenRek(nach, k.rechts) + "))/((" + k.rechts.ToString() + ")^2)";
case "^":
if (k.links.op == "e") return "((" + k.ToString() + ")*(" + AbleitenRek(nach, k.rechts) + "))"; //e-Funktion ableiten
return "(((" + k.links.ToString() + ")^((" + k.rechts.ToString() + ")-1))*(((" + k.rechts.ToString() + ")*(" + AbleitenRek(nach, k.links) + "))+((" + k.links.ToString() + ")*ln(" + k.links.ToString() + ")*(" + AbleitenRek(nach, k.rechts) + "))))";
}
return "0";
}
}
public class Parser
{
public class Knoten
{
Knoten _rechts, _links;
string _op;
public Knoten rechts { get { return _rechts; } set { _rechts = value; } }
public Knoten links { get { return _links; } set { _links = value; } }
public string op { get { return _op; } set { _op = value; } }
public Knoten()
{
this._op = "";
}
public override string ToString()
{
if (this.rechts == null && this.links == null) //nur noch Konstante
return this.op;
if (this.links == null) //z.B. sin(x)
{
if (this.op == "-" && GetPrioritaet(this.rechts.op) > GetPrioritaet(this.op)) return this.op + this.rechts.ToString();
return this.op + "(" + this.rechts.ToString() + ")";
}
//operator mit rechtem und linkem Wert
string l = this.links.ToString();
string r = this.rechts.ToString();
if (GetPrioritaet(this.op) > GetPrioritaet(this.links.op)) l = "(" + l + ")";
if (GetPrioritaet(this.op) > GetPrioritaet(this.rechts.op) || (this.op == "-" && this.rechts.op == "+" || this.op == "/" && this.rechts.op == "*")) r = "(" + r + ")";
return (l + this.op + r);
}
internal bool IsNumber()
{
try
{
double.Parse(this.op);
return true;
}
catch (Exception)
{
}
return false;
}
internal void Null()
{
this.rechts = null;
this.links = null;
}
public void Zuweisung(Knoten k)
{
this.op = k.op;
this.rechts = k.rechts;
this.links = k.links;
}
}
private class Operator
{
string _op;
int _prioritaet;
public string op { get { return _op; } }
public int prioritaet { get { return _prioritaet; } }
public Operator(string op, int prioritaet)
{
this._prioritaet = prioritaet;
this._op = op;
}
}
static Operator[] operatoren = {
new Operator(";", 0), //für Basis bei Logarithmus (/Wurzel)
new Operator("+", 1), new Operator("-", 1),
new Operator("*", 2), new Operator("/", 2),
new Operator("^", 3),
new Operator("sin", 4), new Operator("cos", 4), new Operator("tan", 4), new Operator("lg", 4), new Operator("ln", 4), new Operator("log", 4), new Operator("abs", 4)
};
private static int GetPrioritaet(string operat)
{
foreach (Operator o in operatoren)
if (operat == o.op) return o.prioritaet;
return 10;
}
public Knoten wurzel;
public Parser(string term = "0")
{
term = EinfacheEingabe(term);
wurzel = new Knoten();
wurzel = ParseRek(term, wurzel);
}
public void Simplify()
{
SimplifyRek(wurzel);
}
private void SimplifyRek(Knoten k)
{
if (k.links == null && k.rechts == null) return;
if (k.links != null) SimplifyRek(k.links);
if (k.rechts != null) SimplifyRek(k.rechts);
if (k.links == null)
{
//ist eine Funktion
switch (k.op)
{
case "abs":
if (k.rechts.IsNumber())
{
k.op = Math.Abs(double.Parse(k.rechts.op)).ToString();
k.Null(); return;
}
return;
case "-":
if (k.op == "-" && k.rechts != null && k.rechts.op == "-" && k.rechts.links == null) // -(-(x)) = x
{
k.Zuweisung(k.rechts.rechts); return;
}
return;
}
return;
}
if (k.links != null && k.links != null)
{
bool numL = k.links.IsNumber(); bool numR = k.rechts.IsNumber();
switch (k.op)
{
case "+":
case "-":
if (numL && k.links.op == "0")
{
if (k.op == "+") k.Zuweisung(k.rechts);
else k.links = null;
return;
}
if (numR && k.rechts.op == "0")
{
k.Zuweisung(k.links); return;
}
if (numR && numL)
{
if (k.op == "+") k.op = (double.Parse(k.links.op) + double.Parse(k.rechts.op)).ToString();
if (k.op == "-") k.op = (double.Parse(k.links.op) - double.Parse(k.rechts.op)).ToString();
k.Null(); return;
}
if (k.op == "+" && k.rechts.op == "-" && k.rechts.links == null) // x+(-y) = x-y
{
k.rechts.Zuweisung(k.rechts.rechts); k.op = "-";
return;
}
if (k.op == "-" && k.rechts.op == "-" && k.rechts.links == null) // x-(-y) = x+y
{
k.rechts.Zuweisung(k.rechts.rechts); k.op = "+";
return;
}
return;
case "*":
if (numL && k.links.op == "1")
{
k.Zuweisung(k.rechts); return;
}
if (numR && k.rechts.op == "1")
{
k.Zuweisung(k.links); return;
}
if (numL && k.links.op == "0" || numR && k.rechts.op == "0")
{
k.op = "0"; k.Null(); return;
}
if (numR && numL)
{
k.op = (double.Parse(k.links.op) * double.Parse(k.rechts.op)).ToString();
k.Null(); return;
}
if (!numL && numR) //x*2 zu 2*x drehen
{
Knoten tmp = new Knoten();
tmp.Zuweisung(k);
k.rechts = tmp.links; k.links = tmp.rechts; return;
}
return;
case "/":
if (numR && numL)
{
k.op = (double.Parse(k.links.op) / double.Parse(k.rechts.op)).ToString();
k.Null(); return;
}
return;
case "^":
if (numR && k.rechts.op == "0") //x^0 = 1
{
k.op = "1"; k.Null(); return;
}
if (numR && k.rechts.op == "1")
{
k.Zuweisung(k.links); return;
}
if (numR && numL)
{
k.op = (Math.Pow(double.Parse(k.links.op), double.Parse(k.rechts.op))).ToString();
k.Null(); return;
}
return;
}
return;
}
}
public override string ToString()
{
return wurzel.ToString();
}
private string EinfacheEingabe(string term)
{
term = term.Replace(" ", string.Empty);
term = term.Replace("²", "^2");
term = term.Replace("³", "^3");
term = term.Replace(")(", ")*(");
while (true) //3x zu 3*x; 3sin(x) zu 3*sin(x)
{
Match m = Regex.Match(term, "[0-9][a-zA-Z]");
if (m.Success)
term = term.Insert(m.Index + 1, "*");
else break;
}
int betrag = 0;
for (int i = 0; i < term.Length; i++)
if (term[i] == '|')
{
if (++betrag % 2 == 1) term = term.Remove(i, 1).Insert(i, "abs(");
else term = term.Remove(i, 1).Insert(i, ")");
}
return term;
}
private Knoten ParseRek(string term, Knoten k)
{
string[] s = Parse(term);
if (s[1] == "") //keine Funktion mehr, nur Argument
{
k.op = s[0];
k.Null();
}
else if (s[0] == "") //z.B. sin(x)
{
k.op = s[1];
k.rechts = new Knoten();
k.rechts = ParseRek(s[2], k.rechts);
if (k.op == "+") k.Zuweisung(k.rechts); //unäres Plus im Arsch
k.links = null;
}
else //normaler Operator, mit Wert rechts und links
{
k.op = s[1];
k.rechts = new Knoten();
k.links = new Knoten();
k.links = ParseRek(s[0], k.links);
k.rechts = ParseRek(s[2], k.rechts);
}
return k;
}
private string[] Parse(string term)
{
//finde Operatoren mit niederwertigster Priorität - außerhalb von Klammern
//Durchlaufen von links nach rechts
string[] erg = new string[3];
int klammern = 0, momPrio = 10, stelle = term.Length; string momOp = "";
for (int i = term.Length - 1; i >= 0; i--)
{
if (term[i] == ')') klammern++;
if (term[i] == '(') klammern--;
if (klammern != 0) continue;
foreach (Operator op in operatoren)
{
if (op.prioritaet < momPrio && i + op.op.Length < term.Length && term.Substring(i, op.op.Length) == op.op)
{
momPrio = op.prioritaet;
stelle = i;
momOp = op.op;
}
}
}
if (momPrio == 10 && term.StartsWith("("))
return Parse(term.Substring(1, term.Length - 2));
erg[0] = term.Substring(0, stelle);
erg[1] = momOp;
erg[2] = term.Substring(stelle + momOp.Length);
return erg;
}
} |