В общем можно забивать любые правильные* арифметические выражения и получать результат их вычисления
*правильные - т.е. выражение может состоять только из чисел, разделитель десятичной части - точка, скобок, и бинарных операций +-*/
унарный минус также приветствуется: выражение -3*(5/-2) = -3*(-2.5) = +7.5.
вот 4 примера возможных выражений (приведены как тест):
ex2 := '(-1+(5/2)+3+4+5/2--1*5)'; { +16 }
ex3 := '-2*(2+3)*4+(2*2+1+-5/2)*2+(2*(6/3))'; { -31 }
ex4 := '1*10*100+((0*81))+0.5+(((0.5)))'; { +1001 }
просьба сообщать о найденных багах.
ps в выражение записывать нужно без пробелов. Правильность выражения и баланс скобок не проверяются (пока)
{$N+}
program _SmartCalc;
uses crt;
type
TFloat = Single;
TOperands = array [1..128] of TFloat;
TOperations = array [1..127] of Char;
function FloatToStr(const fValue: TFloat): String;
var
sValue: String;
begin
Str(fValue:0:2, sValue); FloatToStr := sValue;
end;
function StrToFloat(const sValue: String): TFloat;
var
fValue: TFloat;
err: Integer;
begin
Val(sValue, fValue, err); StrToFloat := fValue;
end;
function AtomExpr(const operand_a, operand_b: TFloat;
const operation: Char): TFloat;
begin
case operation of
'+': AtomExpr := operand_a + operand_b;
'-': AtomExpr := operand_a - operand_b;
'*': AtomExpr := operand_a * operand_b;
'/': AtomExpr := operand_a / operand_b;
end;
end;
procedure SimplifyExpr(var operands: TOperands;
var operations: TOperations; var opnds_count, optns_count: Byte);
var
i, j: Byte;
begin
i := 1;
while i <= optns_count do begin
if operations[i] in ['*', '/'] then begin
operands[i] :=
AtomExpr(operands[i], operands[i + 1], operations[i]);
for j := i + 1 to opnds_count - 1 do
operands[j] := operands[j + 1];
dec(opnds_count);
for j := i to optns_count - 1 do
operations[j] := operations[j + 1];
dec(optns_count);
end
else inc(i);
end;
end;
function SubExpr(const s: String): TFloat;
const
ops = '+-*/';
var
operands: TOperands;
operations: TOperations;
opnds_count, optns_count, i, j, len: Byte;
temp: String;
_result: TFloat;
begin
_result := 0;
opnds_count := 0;
optns_count := 0;
len := Length(s);
i := 1;
while i <= len do begin
temp := '';
if (s[i] = '-') and ((i = 1) or (pos(s[i - 1], ops) > 0)) then begin
temp := ConCat(temp, '-');
inc(i);
end;
while (i <= len) and not (s[i] in ['+', '-', '*', '/']) do begin
temp := ConCat(temp, s[i]);
inc(i);
end;
inc(opnds_count);
operands[opnds_count] := StrToFloat(temp);
if i <= len then begin
inc(optns_count);
operations[optns_count] := s[i];
end;
inc(i);
end;
SimplifyExpr(operands, operations, opnds_count, optns_count);
for i := 1 to optns_count do begin
operands[1] := AtomExpr(operands[1], operands[2], operations[i]);
for j := 2 to opnds_count - 1 do
operands[j] := operands[j + 1];
end;
SubExpr := operands[1];
end;
function SmartCalc(const s: String): TFloat;
var
expr, tmp: String;
break_start, break_end, i: Byte;
begin
expr := s;
while Pos('(', expr) > 0 do begin
i := 1;
break_start := 0;
break_end := 0;
repeat
while expr[i] <> '(' do
inc(i);
break_start := i;
inc(i);
while not (expr[i] in ['(', ')']) do
inc(i);
if expr[i] = ')' then
break_end := i;
until break_end > 0;
tmp := Copy(expr, break_start + 1, break_end - break_start - 1);
Delete(expr, break_start, break_end - break_start + 1);
Insert(FloatTOStr(SubExpr(tmp)), expr, break_start);
break_end := 0;
end;
SmartCalc := SubExpr(expr);
end;
var
ex1, ex2, ex3, ex4: String;
begin
clrscr;
ex1 := '10*(5+2*(1-3))'; { +10 }
ex2 := '(-1+(5/2)+3+4+5/2--1*5)'; { +16 }
ex3 := '-2*(2+3)*4+(2*2+1+-5/2)*2+(2*(6/3))'; { -31 }
ex4 := '1*10*100+((0*81))+0.5+(((0.5)))'; { +1001 }
writeln(ex1, ' = ', SmartCalc(ex1):0:2);
writeln(ex2, ' = ', SmartCalc(ex2):0:2);
writeln(ex3, ' = ', SmartCalc(ex3):0:2);
writeln(ex4, ' = ', SmartCalc(ex4):0:2);
readln;
end.
Сообщение отредактировано: klem4 -