首页  编辑  

四则运算代数式转换为浮点数

Tags: /超级猛料/Alogrith.算法和数据结构/数值运算/   Date Created:

作 者: cailu_888(想你~★) 2001-03-07 13:17:46 :0 :0    

将一个包括多重扩号的四则运算代数式转换为浮点数,经典算法是用运算符后置法,再用栈原理计算。小苦想到了一种新颖的算法,用嵌套调用和递归也可以把结果算出来。小苦写成动态链接库TxtToF.dll,VB,Delphi,C++Builder,Visual C++,Java等可以调用。  

源代码如下:  

//动态连接库TxtToF.dll  

library TxtToF;  

uses  

 SysUtils;  

//删除字符串S中的子串SubStr  

function DeleteSubStr(S, SubStr: String): String;  

begin  

 while Pos(SubStr, S) <> 0 do  

   Delete(S, Pos(SubStr, S), Length(SubStr));  

 Result := S;  

end;  

//删除字符串中的所有扩号  

function DeleteK(S: String): String;  

begin  

 S := DeleteSubStr(S, '(');  

 S := DeleteSubStr(S, ')');  

 Result := S;  

end;  

//返回字符串代数式的第一个运算符的整形序号  

function GetOpIndex(S: String): Integer;  

var  

 iAdd, iSub, iMu, iDiv: Integer;  

begin  

 iAdd := Pos('+', S);  

 iSub := Pos('-', S);  

 iMu := Pos('*', S);  

 iDiv := Pos('/', S);  

 if iAdd = 0 then iAdd := 1000;  

 if iSub = 0 then iSub := 1000;  

 if iMu = 0 then iMu := 1000;  

 if iDiv = 0 then iDiv := 1000;  

 if (iAdd < iSub) and (iAdd < iMu) and

(iAdd < iDiv) then Result := iAdd else

if (iSub < iAdd) and (iSub < iMu) and

(iSub < iDiv) then Result := iSub else

if (iMu < iAdd) and (iMu < iSub) and

(iMu < iDiv) then Result := iMu else

if (iDiv < iAdd) and (iDiv < iSub) and

(iDiv < iMu) then Result := iDiv

else

Result := 0;

end;

//消除一个浮点数的前面的多重负号,如"__2"返回"2","___2"返回"_2"

function DeleteMinus(S: String): String;

var

bMinus: Boolean;

begin

bMinus := False;

while S[1] = '_' do

begin

Delete(S, 1, 1);

bMinus := not(bMinus);

end;

if bMinus then Result := '_' + S

else Result := S;

end;

//计算单运算符的代数式,返回浮点数字符串,负号为"_"

function SingleCal(S: String): String;

var

strTemp, strResult: String;

fLeft, fRight: Double;

i, iOpIndex: Integer;

begin

if S[1] = '-' then S[1] := '_';

iOpIndex := GetOpIndex(S);

//要是没有运算符的话,S就是结果

if (iOpIndex = 0) then

begin

Result := S;

exit;

end;

strTemp := ' ';

for i := 0 to iOpIndex - 1 do

strTemp[i] := S[i];

strTemp := Trim(strTemp);

strTemp := DeleteMinus(strTemp);

if strTemp[1] = '_' then

begin

Delete(strTemp, 1, 1);

fLeft := - StrToFloat(strTemp);

end else

fLeft := StrToFloat(strTemp);

strTemp := ' ';

for i := iOpIndex + 1 to Length(S) do

strTemp[i] := S[i];

strTemp := Trim(strTemp);

strTemp := DeleteMinus(strTemp);

if strTemp[1] = '_' then

begin

Delete(strTemp, 1, 1);

fRight := - StrToFloat(strTemp);

end else

fRight := StrToFloat(strTemp);

if S[iOpIndex] = '+' then

strResult := FloatToStr(fLeft + fRight)

else if S[iOpIndex] = '-' then

strResult := FloatToStr(fLeft - fRight)

else if S[iOpIndex] = '*' then

strResult := FloatToStr(fLeft * fRight)

else if S[iOpIndex] = '/' then

strResult := FloatToStr(fLeft / fRight);

if strResult[1] = '-' then

strResult[1] := '_';

Result := strResult;

end;

//计算只有加号或减号的多运算符代数式,返回浮点数字符串,负号为"_"

function AddSubCal(S: String): String;

var

strTemp: String;

iOpIndex, iLeft, iRight, i: Integer;

begin

if S[1] = '-' then S[1] := '_';

//要是没有运算符号,S就是结果

iOpIndex := GetOpIndex(S);

if (iOpIndex = 0) then

begin

Result := SingleCal(S);

exit;

end;

//计算第一条单运算符式子的左浮点数起始位置iLeft

iLeft := iOpIndex - 1;

while (S[iLeft] <> '+') and (S[iLeft] <> '-') and  

 (S[iLeft] <> '*') and (S[iLeft] <> '/') and (S[iLeft] <> '') do  

   iLeft := iLeft - 1;  

 iLeft := iLeft + 1;  

 //计算第一条单运算符式子的右浮点数起始位置iRight  

 iRight := iOpIndex + 1;  

 while (S[iRight] <> '+') and (S[iRight] <> '-') and  

 (S[iRight] <> '*') and (S[iRight] <> '/') and (S[iRight] <> '') do  

   iRight := iRight + 1;  

 iRight := iRight - 1;  

 strTemp := '                                         ';  

 for i := iLeft to iRight do  

   strTemp[i] := S[i];  

 strTemp := Trim(strTemp);  

 Delete(S, iLeft, iRight-iLeft+1);  

 Insert(SingleCal(strTemp), S, iLeft);  

 //递归调用AddSubCal  

 //每调用一次AddSubCal,消除式中的一个运算符,知道没有运算符为止  

 Result := AddSubCal(S);  

end;  

//计算无扩号的多运算符代数式,返回浮点数字符串,负号为"_"  

function NoKCal(S: String): String;  

var  

 strTemp: String;  

 iOpIndex, iMu, iDiv, iLeft, iRight, i: Integer;  

begin  

 if S[1] = '-' then S[1] := '_';  

 iOpIndex := GetOpIndex(S);  

 //要是没有运算符号,S就是结果  

 if (iOpIndex = 0) then  

 begin  

   Result := AddSubCal(S);  

   exit;  

 end;  

 //将负数的负号转为'_'  

 if (iOpIndex = 1) and (S[1] = '-') then  

   S[1] := '_';  

//------------首先考虑运算符等级高的乘号和除号---------------  

 iMu := Pos('*', S);  

 iDiv := Pos('/', S);  

 if (iMu <> 0) or (iDiv <> 0) then  

 begin  

   //乘法运算  

   if ((iMu < iDiv) and (iMu <> 0)) or ((iMu <> 0) and (iDiv = 0)) then  

   begin  

     iLeft := iMu - 1;  

     while (S[iLeft] <> '+') and (S[iLeft] <> '-') and  

     (S[iLeft] <> '*') and (S[iLeft] <> '/') and (S[iLeft] <> '') do  

       iLeft := iLeft - 1;  

     iLeft := iLeft + 1;  

     iRight := iMu + 1;  

     while (S[iRight] <> '+') and (S[iRight] <> '-') and  

     (S[iRight] <> '*') and (S[iRight] <> '/') and (S[iRight] <> '') do  

       iRight := iRight + 1;  

     iRight := iRight - 1;  

     strTemp := '                                         ';  

     for i := iLeft to iRight do  

       strTemp[i] := S[i];  

     strTemp := Trim(strTemp);  

     Delete(S, iLeft, iRight-iLeft+1);  

     Insert(SingleCal(strTemp), S, iLeft);  

     //递归调用NoKCal  

     Result := NoKCal(S);  

     exit;  

   end;  

   //除法运算  

   if (iDiv < iMu) and (iDiv <> 0) or ((iDiv <> 0) and (iMu = 0)) then  

   begin  

     iLeft := iDiv - 1;  

     while (S[iLeft] <> '+') and (S[iLeft] <> '-') and  

     (S[iLeft] <> '*') and (S[iLeft] <> '/') and (S[iLeft] <> '') do  

       iLeft := iLeft - 1;  

     iLeft := iLeft + 1;  

     iRight := iDiv + 1;  

     while (S[iRight] <> '+') and (S[iRight] <> '-') and  

     (S[iRight] <> '*') and (S[iRight] <> '/') and (S[iRight] <> '') do  

       iRight := iRight + 1;  

     iRight := iRight - 1;  

     strTemp := '                                         ';  

     for i := iLeft to iRight do  

       strTemp[i] := S[i];  

     strTemp := Trim(strTemp);  

     Delete(S, iLeft, iRight-iLeft+1);  

     Insert(SingleCal(strTemp), S, iLeft);  

     //递归调用NoKCal,直到没有*号和/号为止  

     Result := NoKCal(S);  

     exit;  

   end;  

 end else  

//---------------------------------------------------------------  

   Result := AddSubCal(S);//S只剩下加号或减号了  

end;  

//计算复杂的代数式字符串,返回浮点数字符串,负号为"_"  

function Cal(S: String): String;  

var  

 strTemp, strOp: String;  

 iLeftK, iRightK, iTemp, i: Integer;  

begin  

 //删除空格  

 S := DeleteSubStr(S, ' ');  

 //要是式子为不带扩号的简单运算式的话  

 if Pos('(', S) = 0 then  

 begin  

   Result := NoKCal(S);  

   exit;  

 end;  

 // 计算出式中最后一个左扩号的位置iLeftK,并把它前面的字符串和它都删除  

 strTemp := S;  

 iTemp := Pos('(', strTemp);  

 iLeftK := - iTemp;  

 while iTemp <> 0 do  

 begin  

   iLeftK := iLeftK + iTemp;  

   iTemp := Pos('(', strTemp);  

   Delete(strTemp, 1, iTemp);  

 end;  

 //strOp是包含左、右扩号的多运算符符式,把扩号删除后交由NoKCal计算  

 strOp := '                                                    ';  

 iRightK := Pos(')', strTemp);  

 for i := 0 to iRightK do  

   strOp[i] := strTemp[i];  

 strOp := '(' + Trim(strOp);  

 //删除多运算符式,用其计算结果代替  

 Delete(S, iLeftK, iRightK+1);  

 strOp := DeleteK(strOp);//删除扩号  

 Insert(NoKCal(strOp), S, iLeftK);  

 //递归调用Cal  

 //每调用一次Cal,式中就计算出式中优先级最高的一对扩号中  

 //多运算符代数式的值,知道没有扩号为止  

 Result := Cal(S);  

end;  

//将Cal算出的结果转化为双精度浮点数  

//此函数符合stdcall约定  

function TxtToFloat(S: String): Double; stdcall;  

begin  

 S := Cal(S);  

 S := DeleteMinus(S);  

 if S[1] = '_' then  

 begin  

   Delete(S, 1, 1);  

   Result := - StrToFloat(S);  

 end else  

 Result := StrToFloat(S);  

end;  

//引出函数  

exports  

 TxtToFloat;  

begin  

end.