fork download
  1. <?php
  2.  
  3. set_error_handler(function ($errno, $errstr, $errfile, $errline ) {
  4. throw new \ErrorException($errstr, $errno, 0, $errfile, $errline);
  5. });
  6.  
  7. bcscale(50); // Количество знаков после запятой по умолчанию
  8.  
  9. class DivideByZeroException extends \Exception
  10. {
  11. public function __construct($numerator)
  12. {
  13. parent::__construct(sprintf("Ошибка: (%s/0) делить на ноль нельзя", $numerator));
  14. }
  15. }
  16.  
  17. class NegativeBaseRootException extends \Exception
  18. {
  19. public function __construct($base)
  20. {
  21. parent::__construct(sprintf("Нельзя получить вещественный корень отрицательного числа %s", $base));
  22. }
  23. }
  24.  
  25. class InvalidInfixException extends \Exception {}
  26.  
  27. class Parser
  28. {
  29. public function getTokensFromInfix($infix)
  30. {
  31. $tokensQueue = new \SplQueue();
  32. $lexems = $this->getLexemsFromInfix($infix);
  33. $binaryOperatorsCount = 0;
  34. $operandsCount = 0;
  35. $parenthesisDeep = 0;
  36.  
  37. foreach ($lexems as $lexem) {
  38. if (is_numeric($lexem)) {
  39. $tokensQueue->push(SimpleFraction::createFromDecimal($lexem));
  40. $operandsCount++;
  41. } elseif (in_array($lexem, ['+', '-'])) {
  42. if ($tokensQueue->isEmpty() || $tokensQueue->top() instanceof LeftParenthesis) {
  43. $tokensQueue->push(OperationFactory::getUnaryBySign($lexem));
  44. } elseif ($tokensQueue->top() instanceof SimpleFraction || $tokensQueue->top() instanceof RightParenthesis) {
  45. $tokensQueue->push(OperationFactory::getBinaryBySign($lexem));
  46. $binaryOperatorsCount++;
  47. } else {
  48. throw new InvalidInfixException(sprintf('В выражении встречаются подряд несколько операторов'));
  49. }
  50. } elseif (in_array($lexem, ['*', '/', '^'])) {
  51. $tokensQueue->push(OperationFactory::getBinaryBySign($lexem));
  52. $binaryOperatorsCount++;
  53. } elseif ($lexem === '(') {
  54. $tokensQueue->push(new LeftParenthesis());
  55. $parenthesisDeep--;
  56. } elseif ($lexem === ')') {
  57. $tokensQueue->push(new RightParenthesis());
  58. $parenthesisDeep++;
  59. } else {
  60. throw new InvalidInfixException(sprintf('Нераспознанная лексема %s', $lexem));
  61. }
  62. }
  63.  
  64. if ($operandsCount !== ++$binaryOperatorsCount) {
  65. throw new InvalidInfixException('Количество бинарных операторов должно быть на один меньше, чем количество чисел');
  66. }
  67. if ($parenthesisDeep !== 0) {
  68. throw new InvalidInfixException('Неправильно расставлены скобки');
  69. }
  70.  
  71. return $tokensQueue;
  72. }
  73.  
  74. private function getLexemsFromInfix($infix)
  75. {
  76. preg_match_all('/(\d+(\.\d+)?|([\+\-\/\*\^\(\)]))|(\S)/', $infix, $match);
  77. if ($invalidChars = array_filter($match[4])) {
  78. throw new InvalidInfixException(sprintf(
  79. 'В инфиксном выражении %s недопустимые символы %s',
  80. $infix,
  81. implode(', ', $invalidChars)
  82. ));
  83. }
  84. $lexems = $match[0];
  85.  
  86. return $lexems;
  87. }
  88. }
  89.  
  90. class ShuntingYard
  91. {
  92. private $operatorStack;
  93.  
  94. public function __construct()
  95. {
  96. $this->operatorStack = new \SplStack;
  97. }
  98.  
  99. public function createRpnQueueFromTokens(\SplQueue $tokens)
  100. {
  101. $outputQueue = new \SplQueue();
  102. foreach ($tokens as $token) {
  103. if ($token instanceof SimpleFraction) {
  104. $outputQueue->enqueue($token);
  105. } elseif ($token instanceof AbstractOperator) {
  106. if ($this->operatorStack->isEmpty()) {
  107. $this->operatorStack->push($token);
  108. continue;
  109. }
  110.  
  111. $operatorTop = $this->operatorStack->top();
  112. if (($operatorTop instanceof AbstractOperator)
  113. && (($token->isLeftassociative() && $token->getPrecedence() <= $operatorTop->getPrecedence())
  114. || ($token->isRightAssociative() && $token->getPrecedence() < $operatorTop->getPrecedence()))
  115. ) {
  116. $outputQueue->enqueue($this->operatorStack->pop());
  117. }
  118.  
  119. $this->operatorStack->push($token);
  120. } elseif ($token instanceof LeftParenthesis) {
  121. $this->operatorStack->push($token);
  122. } elseif ($token instanceof RightParenthesis) {
  123. $operatorTop = $this->operatorStack->top();
  124. if (!$operatorTop instanceof LeftParenthesis) {
  125. $outputQueue->enqueue($this->operatorStack->pop());
  126. }
  127. $this->operatorStack->pop();
  128. } else {
  129. throw new \Exception(sprintf('Invalid type %s given', gettype($token)));
  130. }
  131. }
  132.  
  133. while (!$this->operatorStack->isEmpty()) {
  134. $operatorTop = $this->operatorStack->pop();
  135. if ($operatorTop instanceof LeftParenthesis || $operatorTop instanceof RightParenthesis) {
  136. throw new InvalidInfixException('Mismatched parentheses');
  137. }
  138. $outputQueue->enqueue($operatorTop);
  139. }
  140.  
  141. return $outputQueue;
  142. }
  143. }
  144.  
  145. class Division extends BinaryOperator
  146. {
  147. public static $precedence = 3;
  148. public static $isLeftAssociative = true;
  149.  
  150. public function operate(SimpleFraction $leftOperand, SimpleFraction $rightOperand)
  151. {
  152. if ($rightOperand->getNumerator() === '0') {
  153. throw new DivideByZeroException($leftOperand);
  154. }
  155.  
  156. $newRightOperand = $rightOperand->invert();
  157. $multiplication = new Multiplication();
  158.  
  159. return $multiplication->operate($leftOperand, $newRightOperand);
  160. }
  161. }
  162.  
  163. abstract class AbstractOperator
  164. {
  165. public function getPrecedence()
  166. {
  167. return static::$precedence;
  168. }
  169.  
  170. public function isLeftAssociative()
  171. {
  172. return !! static::$isLeftAssociative;
  173. }
  174.  
  175. public function isRightAssociative()
  176. {
  177. return ! static::$isLeftAssociative;
  178. }
  179. }
  180.  
  181. class Multiplication extends BinaryOperator
  182. {
  183. public static $precedence = 3;
  184. public static $isLeftAssociative = true;
  185.  
  186. public function operate(SimpleFraction $leftOperand, SimpleFraction $rightOperand)
  187. {
  188. $newNumerator = MathHelper::mul($leftOperand->getNumerator(), $rightOperand->getNumerator());
  189. $newDenominator = MathHelper::mul($leftOperand->getDenominator(), $rightOperand->getDenominator());
  190. $isPrecise = $leftOperand->isAccurate() && $rightOperand->isAccurate();
  191.  
  192. return new SimpleFraction($newNumerator, $newDenominator, $isPrecise);
  193. }
  194. }
  195.  
  196. class Power extends BinaryOperator
  197. {
  198. public static $precedence = 4;
  199. public static $isLeftAssociative = false;
  200.  
  201. public function operate(SimpleFraction $leftOperand, SimpleFraction $rightOperand)
  202. {
  203. // Происходит попытка получить корень отрицательного числа
  204. if ($leftOperand->getSign() === SimpleFraction::SIGN_MINUS && !$rightOperand->isInteger()) {
  205. throw new NegativeBaseRootException($leftOperand);
  206. }
  207.  
  208. // Происходит попытка возвести в отрицательную степень
  209. if ($rightOperand->getSign() === SimpleFraction::SIGN_MINUS) {
  210. $newDenominator = $this->operate($leftOperand, $rightOperand->changeSign());
  211. $result = (new Division())->operate(SimpleFraction::createFromDecimal('1'), $newDenominator);
  212.  
  213. return $result;
  214. }
  215.  
  216. // Если возводим в целую степень, то можно использовать bcpow
  217. if ($rightOperand->isInteger()) {
  218. $newNumerator = MathHelper::pow($leftOperand->getNumerator(), $rightOperand->getNumerator());
  219. $newDenominator = MathHelper::pow($leftOperand->getDenominator(), $rightOperand->getDenominator());
  220. $isAccuracy = $leftOperand->isAccurate() && $rightOperand->isAccurate();
  221. } else {
  222. $powerAsFraction = $rightOperand->getNumerator() / $rightOperand->getDenominator();
  223. $newNumerator = pow($leftOperand->getNumerator(), $powerAsFraction);
  224. $newDenominator = pow($leftOperand->getDenominator(), $powerAsFraction);
  225.  
  226. // Определение точности дроби на основе результатов bcpow и pow
  227. if ((MathHelper::pow($newNumerator, $rightOperand->getDenominator())
  228. !== (string) pow($newNumerator, $rightOperand->getDenominator()))
  229. ) {
  230. $isAccuracy = false;
  231. // Из $newNumerator и $newDenumerator нельзя создать дробь, так как эти переменные содержат неточные десятичные дроби
  232. $inaccuracyDecimal = $newNumerator / $newDenominator;
  233.  
  234. return SimpleFraction::createFromDecimal($inaccuracyDecimal, $isAccuracy);
  235. } else {
  236. $isAccuracy = true;
  237. }
  238. }
  239.  
  240. return new SimpleFraction($newNumerator, $newDenominator, $isAccuracy);
  241. }
  242. }
  243.  
  244. class RightParenthesis {}
  245. class Subtraction extends BinaryOperator
  246. {
  247. public static $precedence = 2;
  248. public static $isLeftAssociative = true;
  249.  
  250. public function operate(SimpleFraction $leftOperand, SimpleFraction $rightOperand)
  251. {
  252. $addition = new Addition();
  253. $unaryNegative = new UnaryNegative();
  254. $newRightOperand = $unaryNegative->operate($rightOperand);
  255.  
  256. return $addition->operate($leftOperand, $newRightOperand);
  257. }
  258. }
  259.  
  260. abstract class BinaryOperator extends AbstractOperator
  261. {
  262. abstract function operate(SimpleFraction $leftOperand, SimpleFraction $rightOperand);
  263. }
  264.  
  265. class UnaryPositive extends UnaryOperator
  266. {
  267. public static $precedence = 5;
  268. public static $isLeftAssociative = false;
  269.  
  270. public function operate(SimpleFraction $operand)
  271. {
  272. return $operand;
  273. }
  274. }
  275.  
  276. class LeftParenthesis {}
  277. class Addition extends BinaryOperator
  278. {
  279. public static $precedence = 2;
  280. public static $isLeftAssociative = true;
  281.  
  282. public function operate(SimpleFraction $leftOperand, SimpleFraction $rightOperand)
  283. {
  284. if ($rightOperand->getNumerator() === '0') {
  285. return $leftOperand;
  286. }
  287.  
  288. $commonDenominator = MathHelper::mul($leftOperand->getDenominator(), $rightOperand->getDenominator());
  289. $newNumerator = MathHelper::add(
  290. MathHelper::mul($leftOperand->getDenominator(), $rightOperand->getNumerator()),
  291. MathHelper::mul($leftOperand->getNumerator(), $rightOperand->getDenominator())
  292. );
  293. $isAccurate = $leftOperand->isAccurate() && $rightOperand->isAccurate();
  294.  
  295. return new SimpleFraction($newNumerator, $commonDenominator, $isAccurate);
  296. }
  297. }
  298.  
  299. abstract class UnaryOperator extends AbstractOperator
  300. {
  301. abstract function operate(SimpleFraction $operand);
  302. }
  303.  
  304. class UnaryNegative extends UnaryOperator
  305. {
  306. public static $precedence = 5;
  307. public static $isLeftAssociative = false;
  308.  
  309. public function operate(SimpleFraction $operand)
  310. {
  311. $newSimpleFraction = $operand->changeSign();
  312.  
  313. return $newSimpleFraction;
  314. }
  315. }
  316.  
  317. class OperationFactory
  318. {
  319. public static function getBinaryBySign($sign)
  320. {
  321. switch ($sign) {
  322. case '+': return new Addition();
  323. case '-': return new Subtraction();
  324. case '*': return new Multiplication();
  325. case '/': return new Division();
  326. case '^': return new Power();
  327. default:
  328. throw new \Exception(sprintf('Binary operation %s is not presented', $sign));
  329. }
  330. }
  331.  
  332. public static function getUnaryBySign($sign)
  333. {
  334. switch ($sign) {
  335. case '+': return new UnaryPositive();
  336. case '-': return new UnaryNegative();
  337. default:
  338. throw new \Exception(sprintf('Unary operation %s is not presented', $sign));
  339. }
  340. }
  341. }
  342.  
  343. class MathHelper
  344. {
  345. public static function getGreatestCommonDivisor($a, $b)
  346. {
  347. $gcd = gmp_gcd($a, $b);
  348.  
  349. return gmp_strval($gcd);
  350. }
  351.  
  352. // Удаляет лишние нули после дробной части, которые возникли из-за bcscale(50)
  353. public static function removeTrailingZeros($decimal)
  354. {
  355. $decimal = (string) $decimal;
  356. if (strpos($decimal, '.') === false) {
  357. return $decimal;
  358. }
  359.  
  360. return preg_replace('/\.?0+$/', '', $decimal);
  361. }
  362.  
  363. public static function div($leftString, $rightString)
  364. {
  365. return self::removeTrailingZeros(bcdiv($leftString, $rightString));
  366. }
  367.  
  368. public static function mul($leftString, $rightString)
  369. {
  370. return self::removeTrailingZeros(bcmul($leftString, $rightString));
  371. }
  372.  
  373. public static function add($leftString, $rightString)
  374. {
  375. return self::removeTrailingZeros(bcadd($leftString, $rightString));
  376. }
  377.  
  378. public static function sub($leftString, $rightString)
  379. {
  380. return self::removeTrailingZeros(bcsub($leftString, $rightString));
  381. }
  382.  
  383. public static function pow($leftString, $rightString)
  384. {
  385. return self::removeTrailingZeros(bcpow($leftString, $rightString));
  386. }
  387. }
  388.  
  389. class SimpleFraction
  390. {
  391. private $numerator;
  392. private $denominator;
  393. // Флаг точности
  394. private $isAccurate;
  395.  
  396. const SIGN_PLUS = '+';
  397. const SIGN_MINUS = '-';
  398. const SIGN_INACCURATE = '~';
  399. const SIGN_ACCURATE = '';
  400.  
  401. public function __construct($numerator, $denominator = 1, $isAccurate = true)
  402. {
  403. $this->numerator = MathHelper::removeTrailingZeros($numerator);
  404. $this->denominator = MathHelper::removeTrailingZeros($denominator);
  405. $this->isAccurate = $isAccurate;
  406. $this->simplify();
  407. }
  408.  
  409. public static function createFromDecimal($decimal, $isPrecise = true)
  410. {
  411. preg_match_all('/^(\-?\d+)(?:\.(\d+))?$/', (string) $decimal, $matches);
  412. if (empty(array_filter($matches))) throw new \InvalidArgumentException();
  413. $integerPart = $matches[1][0];
  414. $fractionalPart = empty($matches[2][0]) ? '0' : $matches[2][0];
  415. $denominator = MathHelper::pow('10', strlen($fractionalPart));
  416. $numerator = MathHelper::add(MathHelper::mul($integerPart, $denominator), $fractionalPart);
  417.  
  418. return new self($numerator, $denominator, $isPrecise);
  419. }
  420.  
  421. public function getDenominator()
  422. {
  423. return $this->denominator;
  424. }
  425.  
  426. public function getNumerator()
  427. {
  428. return $this->numerator;
  429. }
  430.  
  431. public function isAccurate()
  432. {
  433. return $this->isAccurate;
  434. }
  435.  
  436. public function invert()
  437. {
  438. list($this->denominator, $this->numerator) = [$this->numerator, $this->denominator];
  439.  
  440. return $this;
  441. }
  442.  
  443. public function getSign()
  444. {
  445. return (strpos($this->numerator, '-') === 0) ? self::SIGN_MINUS : self::SIGN_PLUS;
  446. }
  447.  
  448. public function changeSign()
  449. {
  450. $this->numerator = MathHelper::mul($this->numerator, '-1');
  451.  
  452. return $this;
  453. }
  454.  
  455. // Можно ли дробь представить в виде целого числа
  456. public function isInteger()
  457. {
  458. return !! ($this->denominator === '1' || $this->numerator === '0');
  459. }
  460.  
  461. public function showAsDecimal()
  462. {
  463. return sprintf('%s%s',
  464. $this->getPrecisionSign(),
  465. MathHelper::div($this->numerator, $this->denominator)
  466. );
  467. }
  468.  
  469. private function getPrecisionSign()
  470. {
  471. return ($this->isAccurate()) ? self::SIGN_ACCURATE : self::SIGN_INACCURATE;
  472. }
  473.  
  474. public function __toString()
  475. {
  476. if ($this->numerator === '0') {
  477. $valueAsString = '0';
  478. } elseif (preg_match('/^10*$/', $this->denominator)) {
  479. // Если знаменатель - любая целая степень 10-и, то показать дробь как целое число
  480. $valueAsString = $this->showAsDecimal();
  481. } else {
  482. $valueAsString = sprintf('%s/%s',
  483. $this->numerator,
  484. $this->denominator
  485. );
  486. }
  487.  
  488. return $valueAsString;
  489. }
  490.  
  491. private function simplify()
  492. {
  493. if ($this->numerator === '0') {
  494. return;
  495. }
  496.  
  497. // Упрощение дроби с использованием НОД
  498. $gcd = MathHelper::getGreatestCommonDivisor($this->numerator, $this->denominator);
  499. $this->numerator = MathHelper::div($this->numerator, $gcd);
  500. $this->denominator = MathHelper::div($this->denominator, $gcd);
  501.  
  502. // Если знаменатель отрицательный - перенести минус в числитель
  503. if (strpos($this->denominator, '-') === 0) {
  504. $this->denominator = substr($this->denominator, 1);
  505. $this->numerator = MathHelper::mul($this->numerator, '-1');
  506. }
  507. }
  508. }
  509.  
  510. class RpnQueueEvaluator
  511. {
  512. private $stack;
  513.  
  514. public function __construct()
  515. {
  516. $this->stack = new \SplStack;
  517. }
  518.  
  519. public function evaluate(\SplQueue $tokens)
  520. {
  521. foreach ($tokens as $token) {
  522. if ($token instanceof SimpleFraction) {
  523. $this->stack->push($token);
  524. } elseif ($token instanceof AbstractOperator) {
  525. if ($token instanceof BinaryOperator) {
  526. $rightOperand = $this->stack->pop();
  527. $leftOperand = $this->stack->pop();
  528. $fraction = $token->operate($leftOperand, $rightOperand);
  529. } elseif ($token instanceof UnaryOperator) {
  530. $operand = $this->stack->pop();
  531. $fraction = $token->operate($operand);
  532. } else {
  533. throw new \Exception(sprintf('Invalid type %s given', gettype($token)));
  534. }
  535.  
  536. $this->stack->push($fraction);
  537. } else {
  538. throw new \InvalidArgumentException();
  539. }
  540. }
  541.  
  542. return $this->stack->top();
  543. }
  544. }
  545.  
  546. $infix_correctAnswer = [
  547. '1/1000' => '0.001',
  548. '100/1' => '100',
  549. '123456789123456789123456789/100' => '1234567891234567891234567.89',
  550. '1230/100' => '12.3',
  551. '2^(1/2)' => SimpleFraction::SIGN_INACCURATE . pow(2, 1/2),
  552. '-2 ^ 2' => '4',
  553. '-2 ^ (-1/2)' => 'NegativeBaseRoot',
  554. '8 ^ (-2/3)' => '1/4',
  555. '16 ^ 0.75' => '8',
  556. '(9/1) ^ (1/2)' => '3',
  557. '2/3 ^ 2' => '2/9',
  558. '3 ^ 2 ^ 2' => '81',
  559. '9 ^ 0' => '1',
  560. '9 ^ 2 ^ 0' => '9',
  561. '3-(-2)' => '5',
  562. '(+2)' => '2',
  563. '+(-2)' => '-2',
  564. '-(-1)' => '1',
  565. '(5+7)*(-3-(-1))' => '-24',
  566. '3+-2' => 'InvalidInfix',
  567. '-(+(+(-3)))' => '3',
  568. '2-(-2)' => '4',
  569. '(-2)*(-3)' => '6',
  570. '10/(-1)*(-2)' => '20',
  571. '(-3)-(-3)' => '0',
  572. '2+4-(-2)' => '8',
  573. '0 - (-3)' => '3',
  574. '1 - 3' => '-2',
  575. '0 - 3' => '-3',
  576. '(2 + 6) / (1 - 1)' => 'DivideByZero',
  577. '0 / 0' => 'DivideByZero',
  578. '-0' => '0',
  579. '0/2' => '0',
  580. '17654/342' => '8827/171',
  581. '4 - 3' => ' 1',
  582. '2 + (-3)' => '-1',
  583. '4 * 5' => '20',
  584. '6/4' => '3/2',
  585. '1.2 + 1/2' => '1.7',
  586. '1/(-3)' => '-1/3',
  587. '0.5 + 0.2' => '0.7',
  588. '(((' => 'InvalidInfix',
  589. '(1+2) * (4-2))' => 'InvalidInfix',
  590. '+ +' => 'InvalidInfix',
  591. '-3' => '-3',
  592. '+3-' => 'InvalidInfix',
  593. '1 2 3' => 'InvalidInfix',
  594. '>34%; + 3w' => 'InvalidInfix',
  595. '1)' => 'InvalidInfix',
  596. '0.000000000000000000000000001 + 0.000000000000000000000000002' => '0.000000000000000000000000003',
  597. ];
  598.  
  599. $parser = new Parser;
  600. $shuntingYard = new ShuntingYard;
  601. $rpnQueueEvaluator = new RpnQueueEvaluator;
  602.  
  603. echo sprintf('Выражение в инфиксной нотации %7s Ожидается %11s Получено', '', '');
  604. foreach ($infix_correctAnswer as $infix => $correctAnswer) {
  605. echo sprintf("\n%29s %17s ", $infix, $correctAnswer);
  606. try {
  607. $tokenQueue = $parser->getTokensFromInfix($infix);
  608. $rpnQueue = $shuntingYard->createRpnQueueFromTokens($tokenQueue);
  609. $result = $rpnQueueEvaluator->evaluate($rpnQueue);
  610. echo sprintf('%20s', $result);
  611. } catch (InvalidInfixException $e) {
  612. echo $e->getMessage();
  613. } catch (DivideByZeroException $e) {
  614. echo $e->getMessage();
  615. } catch (NegativeBaseRootException $e) {
  616. echo $e->getMessage();
  617. }
  618. }
  619.  
Success #stdin #stdout 0.05s 52480KB
stdin
Standard input is empty
stdout
Выражение в инфиксной нотации         Ожидается             Получено
                       1/1000             0.001                0.001
                        100/1               100                  100
123456789123456789123456789/100 1234567891234567891234567.89 1234567891234567891234567.89
                     1230/100              12.3                 12.3
                      2^(1/2)  ~1.4142135623731     ~1.4142135623731
                       -2 ^ 2                 4                    4
                  -2 ^ (-1/2)  NegativeBaseRoot Нельзя получить вещественный корень отрицательного числа -2
                   8 ^ (-2/3)               1/4                  1/4
                    16 ^ 0.75                 8                    8
                (9/1) ^ (1/2)                 3                    3
                      2/3 ^ 2               2/9                  2/9
                    3 ^ 2 ^ 2                81                   81
                        9 ^ 0                 1                    1
                    9 ^ 2 ^ 0                 9                    9
                       3-(-2)                 5                    5
                         (+2)                 2                    2
                        +(-2)                -2                   -2
                        -(-1)                 1                    1
              (5+7)*(-3-(-1))               -24                  -24
                         3+-2      InvalidInfix В выражении встречаются подряд несколько операторов
                  -(+(+(-3)))                 3                    3
                       2-(-2)                 4                    4
                    (-2)*(-3)                 6                    6
                 10/(-1)*(-2)                20                   20
                    (-3)-(-3)                 0                    0
                     2+4-(-2)                 8                    8
                     0 - (-3)                 3                    3
                        1 - 3                -2                   -2
                        0 - 3                -3                   -3
            (2 + 6) / (1 - 1)      DivideByZero Ошибка: (8/0) делить на ноль нельзя
                        0 / 0      DivideByZero Ошибка: (0/0) делить на ноль нельзя
                           -0                 0                    0
                          0/2                 0                    0
                    17654/342          8827/171             8827/171
                        4 - 3                 1                    1
                     2 + (-3)                -1                   -1
                        4 * 5                20                   20
                          6/4               3/2                  3/2
                    1.2 + 1/2               1.7                  1.7
                       1/(-3)              -1/3                 -1/3
                    0.5 + 0.2               0.7                  0.7
                          (((      InvalidInfix Количество бинарных операторов должно быть на один меньше, чем количество чисел
               (1+2) * (4-2))      InvalidInfix Неправильно расставлены скобки
                          + +      InvalidInfix В выражении встречаются подряд несколько операторов
                           -3                -3                   -3
                          +3-      InvalidInfix Количество бинарных операторов должно быть на один меньше, чем количество чисел
                        1 2 3      InvalidInfix Количество бинарных операторов должно быть на один меньше, чем количество чисел
                   >34%; + 3w      InvalidInfix В инфиксном выражении >34%; + 3w недопустимые символы >, %, ;, w
                           1)      InvalidInfix Неправильно расставлены скобки
0.000000000000000000000000001 + 0.000000000000000000000000002 0.000000000000000000000000003 0.000000000000000000000000003