ScEvaluate.pas 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786
  1. unit ScEvaluate;
  2. interface
  3. function Evaluate(formula: string; var status,location: integer) : double; overload;
  4. function Evaluate(formula: string):double; overload;
  5. implementation
  6. function Evaluate(formula: string):double;
  7. var
  8. iStatus: Integer;
  9. iLocation: Integer;
  10. begin
  11. Result := Evaluate(formula, iStatus, iLocation);
  12. end;
  13. {================================== EVALUATE ================================}
  14. { ------------------------------- Declarations ----------------------------- }
  15. const MaxReal = 1.0E+37; { Maximum real value that we will allow }
  16. MaxFact = 33; { 33! = E+37 }
  17. MaxExpo = 85; { exp(85) = E+37 }
  18. var Region, { Check if result is defined. eg fact(-1.2) }
  19. Divzero, { Check if a division by zero occured. eg 1/0 }
  20. Overflow, { Check if result becomes too large. eg 100! }
  21. Complex : boolean; { Check if result is complex. eg sqrt(-1) }
  22. { -------------------------------------------------------------------------- }
  23. {============================================================================}
  24. {================================== EVALUATE ================================}
  25. { From a VERY VERY OLD Pascal 3.0 Function !
  26. {============================================================================}
  27. { Initialize boolean flags. }
  28. procedure Init_Booleans;
  29. begin
  30. region:=true; { Result is initially inside region }
  31. complex:=false; { Result is not complex }
  32. divzero:=false; { There is no division by zero }
  33. overflow:=false; { and no overflow. }
  34. end; { Init_Booleans }
  35. { Check to see if doing an operation on a and b will cause an overflow and
  36. set the OVERFLOW boolean accordingly }
  37. procedure CheckOverflow(a,b: real; operation: char);
  38. begin
  39. case operation of
  40. '*': if abs(a) > 1.0 then overflow:=abs(b) > MaxReal/abs(a);
  41. '/': if b <> 0.0 then
  42. begin
  43. b:=1/b;
  44. if abs(a) > 1.0 then overflow:=abs(b) > MaxReal/abs(a)
  45. end
  46. else overflow:=true;
  47. '+': if b > 0.0 then overflow:=a > (MaxReal - b)
  48. else overflow:=a < (-MaxReal - b);
  49. '-': if b < 0.0 then overflow:=a > (MaxReal + b)
  50. else overflow:=a < (-MaxReal + b);
  51. else overflow:=true; { Default for bad operation }
  52. end; { case }
  53. end; { CheckOverflow }
  54. { ----------------------------------------------------------------------------
  55. The following functions -- asin,acos,tan,cot,sec,csc,sinh,cosh,tanh,sech,
  56. csch,coth,fact -- will default to 0.0 if a division by zero occurs, the
  57. result is complex or undefined, or if an overflow occurs.
  58. If you are using these functions independently of the Evaluate procedure
  59. then the procedure Init_Booleans should be called first to reinitialize
  60. error checking.
  61. ---------------------------------------------------------------------------- }
  62. { --- Arc Sine --- }
  63. function Asin(r: real): real;
  64. begin
  65. if abs(r) < 1.0 then asin:=arctan(r/sqrt(1-r*r))
  66. else
  67. if abs(r) = 1.0 then asin:=(r/abs(r))*pi/2
  68. else
  69. begin
  70. asin:=0.0;
  71. complex:=true
  72. end { else }
  73. end; { asin }
  74. { --- Arc Cosine --- }
  75. function Acos(r: real): real;
  76. begin
  77. if r = 0.0 then acos:=pi/2
  78. else
  79. begin
  80. if abs(r) < 1.0 then
  81. begin
  82. if r < 0.0 then acos:=arctan(sqrt(1-r*r)/r)+pi
  83. else acos:=arctan(sqrt(1-r*r)/r)
  84. end
  85. else
  86. if abs(r) = 1.0 then
  87. if r = 1.0 then acos:=0.0
  88. else acos:=pi
  89. else
  90. begin
  91. acos:=0.0;
  92. complex:=true
  93. end
  94. end
  95. end; { acos }
  96. { --- Tangent --- }
  97. function Tan(r: real): real;
  98. begin
  99. if cos(r) = 0.0 then
  100. begin
  101. tan:=0.0;
  102. divzero:=true
  103. end
  104. else tan:=sin(r)/cos(r)
  105. end; { tan }
  106. { --- CoTangent --- }
  107. function Cot(r: real): real;
  108. begin
  109. if sin(r) = 0.0 then
  110. begin
  111. cot:=0.0;
  112. divzero:=true
  113. end
  114. else cot:=cos(r)/sin(r)
  115. end; { cot }
  116. { --- Secant --- }
  117. function Sec(r: real): real;
  118. begin
  119. if cos(r) = 0.0 then
  120. begin
  121. sec:=0.0;
  122. divzero:=true
  123. end
  124. else sec:=1/cos(r)
  125. end; { Sec }
  126. { --- CoSecant --- }
  127. function Csc(r: real): real;
  128. begin
  129. if sin(r) = 0.0 then
  130. begin
  131. csc:=0.0;
  132. divzero:=true
  133. end
  134. else csc:=1/sin(r)
  135. end; { Csc }
  136. { --- Sinh --- }
  137. function Sinh(r: real): real;
  138. begin
  139. if abs(r) <= MaxExpo then sinh:=(exp(r)-exp(-r))/2
  140. else
  141. begin
  142. overflow:=true;
  143. sinh:=0.0
  144. end
  145. end; { Sinh }
  146. { --- CoSinh --- }
  147. function Cosh(r: real): real;
  148. begin
  149. if abs(r) <= MaxExpo then cosh:=(exp(r)+exp(-r))/2
  150. else
  151. begin
  152. overflow:=true;
  153. cosh:=0.0
  154. end
  155. end; { Cosh }
  156. { --- Tanh --- }
  157. function Tanh(r: real): real;
  158. begin
  159. if cosh(r) = 0.0 then
  160. begin
  161. tanh:=0.0;
  162. divzero:=true
  163. end
  164. else
  165. begin
  166. CheckOverflow(sinh(r),cosh(r),'/');
  167. if not overflow then tanh:=sinh(r)/cosh(r)
  168. else tanh:=0.0
  169. end
  170. end; { Tanh }
  171. { --- Sech --- }
  172. function Sech(r: real): real;
  173. begin
  174. if cosh(r) = 0.0 then
  175. begin
  176. sech:=0.0;
  177. divzero:=true
  178. end
  179. else
  180. begin
  181. CheckOverflow(1,cosh(r),'/');
  182. if not overflow then sech:=1/cosh(r)
  183. else sech:=0.0
  184. end
  185. end; { Sech }
  186. { --- CoSech --- }
  187. function Csch(r: real): real;
  188. begin
  189. if sinh(r) = 0.0 then
  190. begin
  191. csch:=0.0;
  192. divzero:=true
  193. end
  194. else
  195. begin
  196. CheckOverflow(1,sinh(r),'/');
  197. if not overflow then csch:=1/sinh(r)
  198. else csch:=0.0
  199. end
  200. end; { Csch }
  201. { --- CoTanh --- }
  202. function Coth(r: real): real;
  203. begin
  204. if sinh(r) = 0.0 then
  205. begin
  206. coth:=0.0;
  207. divzero:=true
  208. end
  209. else
  210. begin
  211. CheckOverflow(cosh(r),sinh(r),'/');
  212. if not overflow then coth:=cosh(r)/sinh(r)
  213. else coth:=0.0
  214. end
  215. end; { Coth }
  216. { --- Factorial --- }
  217. function Fact(r:real): real;
  218. var i: integer;
  219. resulta: real;
  220. begin
  221. if (r < 0.0) or (trunc(r) <> r) then
  222. begin
  223. resulta:=0.0;
  224. region:=false
  225. end
  226. else
  227. begin
  228. resulta:=1.0;
  229. if trunc(r) < MaxFact then
  230. for i:=1 to trunc(r) do
  231. resulta:=resulta*i
  232. else
  233. begin
  234. overflow:=true;
  235. resulta:=0.0
  236. end
  237. end;
  238. fact:=resulta
  239. end; { Fact }
  240. { ----------------------------------------------------------------------------
  241. The function Evaluate is passed a mathematical expression in the form of a
  242. string (formula) to be evaluated and returns the following:
  243. If no errors occur during evaluation then:
  244. Result = evaluated expression
  245. Status = 0
  246. Location = 0
  247. If an error occurs then:
  248. Result = 0.0
  249. Status = error type
  250. Location = location of error in formula
  251. Error types:
  252. 0: No error occured
  253. 1: Illegal character
  254. 2: Incorrect syntax
  255. 3: Illegal or missing parenthese
  256. 4: Incorrect real format
  257. 5: Illegal function
  258. 6: Result is undefined
  259. 7: Result is too large
  260. 8: Result is complex
  261. 9: Division by zero
  262. ---------------------------------------------------------------------------- }
  263. {const
  264. ErrStr: array[1..9] of string =
  265. ('无效字符',
  266. '语法错误',
  267. '括号不配对',
  268. '实数的格式部正确',
  269. );}
  270. function Evaluate(formula: string; var status,location: integer):double;
  271. { ---- Declaration ---- }
  272. const numbers: set of char = ['0'..'9']; { Digits }
  273. RightPar: set of char = [')',']','}']; { Right parentheses }
  274. LeftPar: set of char = ['(','[','{']; { Left parentheses }
  275. alpha: set of char = ['A'..'Z']; { Alpha characters }
  276. operators: set of char = ['+','-','*','/','^']; { Operators }
  277. eofline = ^M;
  278. var ch: char; { Current character }
  279. resulto: real; { Final value }
  280. { ---- Internal routines ---- }
  281. { Check to see if an error has occured }
  282. function Ok: boolean;
  283. begin
  284. ok:= region and (not divzero) and (not complex)
  285. and (not overflow) and (status = 0);
  286. end; { Ok }
  287. { Get the next character in the string and increment the location pointer. }
  288. procedure NextCh;
  289. begin
  290. repeat
  291. location:=location+1; { Increment pointer }
  292. if location <= length(formula) then ch:=formula[location]
  293. else ch:=eofline;
  294. if not (ch in alpha + numbers + LeftPar + RightPar + operators
  295. + ['%', '.',' ','!',eofline]) then
  296. status:=1; { Illegal char. }
  297. until ch <> ' '; { Skip blanks }
  298. end { NextCh };
  299. { ---- Nested functions ---- }
  300. function Expression: real;
  301. label quit;
  302. var e,e_hold: real;
  303. opr: char;
  304. Leading_Sign,Nested_Function: boolean;
  305. function SimpleExpression: real;
  306. label quit;
  307. var s,s_hold: real;
  308. opr: char;
  309. function Term: real;
  310. label quit;
  311. var t,t_hold: real;
  312. function SignedFactor: Real;
  313. function Factor: Real;
  314. label quit;
  315. type StandardFunction =
  316. (fpi,fabs,fsqrt,fsqr,fln,flog,fexp,ffact,
  317. fsinh,fcosh,ftanh,fsech,fcsch,fcoth,
  318. fsin,fcos,ftan,fsec,fcsc,fcot,fasin,facos,fatan);
  319. StandardFunctionList = array[StandardFunction] of string[4];
  320. const StandardFunctionNames: StandardFunctionList =
  321. ('PI','ABS','SQRT','SQR','LNG','LOG','EXP','FACT',
  322. 'SINH','COSH','TANH','SECH','CSCH','COTH',
  323. 'SIN','COS','TAN','SEC','CSC','COT','ASIN','ACOS','ATAN');
  324. var Found: Boolean;
  325. l: integer;
  326. F: Real;
  327. str: string;
  328. Sf: StandardFunction;
  329. start,position: integer;
  330. begin { Function Factor }
  331. { Exit if error }
  332. if not ok then begin f:=0.0; goto quit end;
  333. { Get a real or integer expression }
  334. if ch in numbers+['.'] then
  335. begin
  336. start:=location;
  337. if ch in numbers then repeat NextCh until not (ch in numbers);
  338. if ch = '.' then repeat NextCh until not (ch in numbers);
  339. { Get the E format of a real expression }
  340. if ch = 'E' then
  341. begin
  342. NextCh;
  343. if ch = 'X' then location:=location - 1 { Skip EXP(...) }
  344. else
  345. if not (ch in numbers + ['+','-']) then status:=4
  346. else repeat NextCh until not (ch in numbers);
  347. end;
  348. { Check the real format }
  349. str:=copy(formula,start,location-start);
  350. { Remove all spaces in str otherwise val will bomb! }
  351. while pos(' ',str) <> 0 do delete(str,pos(' ',str),1);
  352. val(str,f,position);
  353. if position <> 0 then
  354. begin
  355. location:=start+position;
  356. status:=4 { Incorrect Real format }
  357. end;
  358. if Ok and (Ch = '%') then
  359. begin
  360. f := f / 100;
  361. NextCh;
  362. end;
  363. end { end if ch in number }
  364. { The character is not a digit }
  365. else
  366. begin
  367. { Check for for the beginning of a "sub" expression }
  368. if ch in LeftPar then
  369. begin
  370. NextCh;
  371. F:=Expression; { RECURSION !!! }
  372. if ok and (ch in RightPar) then { Check for implicit * }
  373. begin
  374. NextCh;
  375. if not (ch in operators+LeftPar+RightPar+['!',eofline]) then
  376. begin
  377. ch:='*';
  378. location:=location-1
  379. end;
  380. end
  381. else status:=3 { Illegal parenthese }
  382. end { if ch in LeftPar }
  383. { It should be a function }
  384. else
  385. begin
  386. found:=false;
  387. { Search for the function among our list }
  388. for sf:=fpi to fatan do
  389. if not found then
  390. begin
  391. l:=length(StandardFunctionNames[sf]);
  392. if copy(formula,location,l)=StandardFunctionNames[sf] then
  393. begin
  394. location:=location+l-1;
  395. NextCh;
  396. if sf <> fpi then
  397. begin
  398. Nested_Function:=true;
  399. F:=Factor
  400. end;
  401. { Assign values according to the function }
  402. case sf of
  403. fpi: f:=pi; { pi is predefined }
  404. fsqr: if f < 1.0e+19 then f:=sqr(f)
  405. else
  406. begin
  407. f:=0.0;
  408. overflow:=true
  409. end;
  410. fabs: f:=abs(f);
  411. fsqrt: if f < 0.0 then
  412. begin
  413. complex:=true;
  414. f:=0.0
  415. end
  416. else f:=sqrt(f);
  417. fsin: f:=sin(f);
  418. fcos: f:=cos(f);
  419. ftan: f:=tan(f);
  420. fasin: f:=asin(f);
  421. facos: f:=acos(f);
  422. fatan: f:=arctan(f);
  423. fsec: f:=sec(f);
  424. fcsc: f:=csc(f);
  425. fcot: f:=cot(f);
  426. fsinh: f:=sinh(f);
  427. fcosh: f:=cosh(f);
  428. ftanh: f:=tanh(f);
  429. fsech: f:=sech(f);
  430. fcsch: f:=csch(f);
  431. fcoth: f:=coth(f);
  432. fexp: if abs(f) < MaxExpo then f:=exp(f)
  433. else
  434. if f < 0 then f:=0.0
  435. else
  436. begin
  437. overflow:=true;
  438. f:=0.0
  439. end;
  440. ffact: f:=fact(f);
  441. fln : if f < 0.0 then
  442. begin
  443. complex:=true;
  444. f:=0.0
  445. end
  446. else
  447. if f = 0.0 then
  448. begin
  449. overflow:=true;
  450. f:=0.0
  451. end
  452. else f:=ln(f);
  453. flog: if f < 0.0 then
  454. begin
  455. complex:=true;
  456. f:=0.0
  457. end
  458. else
  459. if f = 0.0 then
  460. begin
  461. overflow:=true;
  462. f:=0.0
  463. end
  464. else f:=ln(f)/ln(10);
  465. end; { Case }
  466. found:=true;
  467. Nested_Function:=false;
  468. { Check for a trailing factorial symbol }
  469. if ch = '!' then
  470. begin
  471. f:=fact(f);
  472. NextCh
  473. end
  474. end { If copy = function }
  475. end; { If not found }
  476. { Check for more errors }
  477. if (not found) and ok and not (ch in alpha) then
  478. status:=2; { Illegal Syntax }
  479. if (not found) and ok and (ch in alpha) then
  480. status:=5; { Illegal function }
  481. end { Else not ch in LeftPar .. ie. it should be a function }
  482. end; { else the character is not a digit }
  483. { Check for a trailing factorial symbol }
  484. if ok and (not Nested_Function) and (ch = '!') then
  485. begin
  486. f:=fact(f);
  487. NextCh
  488. end;
  489. { Assign final value }
  490. quit: Factor:=F
  491. end; { Factor inside SignedFactor }
  492. begin { SignedFactor }
  493. if ch = '-' then
  494. begin
  495. NextCh;
  496. SignedFactor:= -Factor
  497. end
  498. else SignedFactor:=Factor;
  499. end { SignedFactor inside Term };
  500. begin { Term }
  501. if not ok then begin t:=0.0; goto quit end; { Exit }
  502. t:=SignedFactor;
  503. while ch = '^' do
  504. begin
  505. if not ok then begin t:=0.0; goto quit end; { Exit }
  506. NextCh;
  507. t_hold:=SignedFactor;
  508. { Check for illegal power }
  509. if ((t < 0.0) and ((t_hold-trunc(t_hold)) <> 0.0)) or (t = 0.0) then
  510. begin
  511. t:=0.0;
  512. complex:=true
  513. end
  514. { Power is legal }
  515. else
  516. begin
  517. if t < 0.0 then
  518. begin
  519. CheckOverflow(ln(-t),t_hold,'*');
  520. if not Ok then begin t:=0.0; goto quit end; { Exit }
  521. if ln(-t)*t_hold <= MaxExpo then
  522. case trunc(abs(t_hold)) mod 2 = 0 of
  523. true: t:=exp(ln(-t)*t_hold);
  524. false: t:=-exp(ln(-t)*t_hold)
  525. end
  526. else
  527. begin
  528. t:=0.0;
  529. overflow:=true
  530. end
  531. end { if t < 0.0 }
  532. else { t >= 0.0 }
  533. begin
  534. CheckOverflow(ln(t),t_hold,'*');
  535. if not Ok then begin t:=0.0; goto quit end; { Exit }
  536. if ln(t)*t_hold <= MaxExpo then t:=exp(ln(t)*t_hold)
  537. else
  538. begin
  539. t:=0.0;
  540. overflow:=true
  541. end
  542. end { else t >= 0.0 }
  543. end { else not illegal power }
  544. end; { while }
  545. quit: Term:=t;
  546. end; { Term inside SimpleExpression }
  547. begin { SimpleExpression }
  548. if not ok then begin s:=0.0; goto quit end; { Exit }
  549. s:=term;
  550. { Check for implicit multiplication and insert missing "*" }
  551. if ok and (ch in LeftPar + alpha + numbers + ['.']) then
  552. begin
  553. ch:='*';
  554. location:=location-1
  555. end;
  556. while ch in ['*','/'] do
  557. begin
  558. if not ok then begin s:=0.0; goto quit end; { Exit }
  559. opr:=ch;
  560. NextCh;
  561. { Check for implicit multiplication and insert missing "*" }
  562. if opr in LeftPar + alpha + numbers + ['.'] then
  563. begin
  564. opr:='*';
  565. ch:='(';
  566. location:=location-1
  567. end;
  568. s_hold:=term;
  569. case opr of
  570. '*': begin
  571. CheckOverflow(s,s_hold,'*');
  572. if not overflow then s:=s*s_hold
  573. else s:=0.0
  574. end;
  575. '/': begin
  576. divzero:=s_hold = 0.0;
  577. if not divzero then
  578. begin
  579. CheckOverflow(s,s_hold,'/');
  580. if not overflow then s:=s/s_hold
  581. else s:=0.0
  582. end
  583. else s:=0.0
  584. end
  585. end; { Case }
  586. { Check for implicit multiplication and insert missing "*" }
  587. if ok and (ch in LeftPar + alpha + numbers + ['.']) then
  588. begin
  589. ch:='*';
  590. location:=location-1
  591. end
  592. end; { while }
  593. { Assign final value }
  594. quit: SimpleExpression:=s;
  595. end; { SimpleExpression inside Expression }
  596. begin { Expression }
  597. if not ok then begin e:=0.0; goto quit end; { Exit }
  598. Nested_Function:=false;
  599. Leading_Sign:= ch = '-'; { The default is + }
  600. if ch in ['+','-'] then Nextch; { Skip leading sign }
  601. case Leading_Sign of { Set for leading sign }
  602. true: e:= -SimpleExpression;
  603. false: e:= SimpleExpression
  604. end;
  605. while ch in ['+','-'] do
  606. begin
  607. if not ok then begin e:=0.0; goto quit end; { Exit }
  608. opr:=ch;
  609. NextCh;
  610. e_hold:=SimpleExpression;
  611. case opr of
  612. '+': begin
  613. CheckOverflow(e,e_hold,'+');
  614. if not overflow then e:=e+e_hold
  615. else e:=0.0;
  616. end;
  617. '-': begin
  618. CheckOverflow(e,e_hold,'-');
  619. if not overflow then e:=e-e_hold
  620. else e:=0.0;
  621. end;
  622. end; { case }
  623. end; { while }
  624. quit: Expression:=e;
  625. end; { Expression inside Evaluate }
  626. var i:integer;
  627. begin { Evaluate }
  628. { Initialize }
  629. for i:=1 to length(formula) do
  630. formula[i]:=upcase(formula[i]);
  631. Init_Booleans;
  632. status:=0;
  633. location:=0;
  634. NextCh;
  635. { Get result }
  636. resulto:=Expression;
  637. { Check for final errors }
  638. if ok then if ch <> eofline then status:=2; { Incorrect Syntax }
  639. if not region then status:=6;
  640. if overflow then status:=7;
  641. if complex then status:=8;
  642. if divzero then status:=9;
  643. if status in [4,6..9] then location:=location-1;
  644. if status = 0 then location:=0
  645. else resulto:=0.0;
  646. Evaluate:=resulto;
  647. end { Evaluate };
  648. end.