calc
Калькулятор, работающий на Обратной польской нотации.
Основной класс - Expression
.
Он является неизменяемым и представляет скомпилированное арифметическое выражение.
В выражении поддерживаются следующие операции и функции:
+
-- сложение-
,−
-- вычитание*
,∙
,∗
,×
,✕
-- умножение/
,÷
,∕
-- деление^
-- возведение в степень!
-- факториал%
-- перевод в проценты√
,sqrt
-- радикал (квадратный корень)log
-- логирифм по основанию 10ln
-- натуральный логарифмexp
-- экспонентаabs
-- абсолютная величинаsgn
-- сигнумsin
-- синусcos
-- косинусtan
,tg
-- тангенсcot
,ctg
-- котангенсarcsin
-- арксинусarccos
-- арккосинусarctan
,arctg
-- арктангенсarccot
,arcctg
-- арккотангенсsinh
,sh
-- гиперболический синусcosh
,ch
-- гиперболический косинусtanh
,th
-- гиперболический тангенсcoth
,cth
-- гиперболический котангенс
Выражение может содержать в себе именованные константы. Грамматика констант и допустимые символы позаимствованы у языка Java, поэтому все символы, которые могут быть идентификаторами в Java, могут также быть константами в выражении. Допустимые имена констант:
a, b, c, const1
значение1, значение2, высота, ширина
Константы не могут иметь те же имена что и функции. Помимо этого, для выражения зарезервированы математические константы:
Синтаксис арифметических выражений близок к класическому, но имеет некоторые улучшения. Символы пробела, переносов строки и табуляции используются как разделители операндов, если написать два операнда раздельно, это будет эквивалентно операции умножения. Кроме этого, десятичные дроби можно записывать, опуская ноль перед точкой. Так, следующие выражения полностью эквивалентны:
2a <==> 2 a <==> 2 * a
sin pi <==> sin(pi)
√-4 <==> √(-4)
0.24 <==> .24
0. <==> .0 <==> . <==> 0
(2a sin 3)(a b cos c) <==> (2*a*sin(3))*(a*b*cos(c))
Использование
Подключение:
import mitasov.calc.Expression;
Простой пример:
Expression e = new Expression("2+2"); //целые числа
double res1 = e.evaluate(); // == 4
e = new Expression("2.564 * 2"); //дробные
res = e.evaluate(); // == 5.128
e = new Expression("2,5 - 3", ',') //можно указать символ плавающей точки
res = e.evaluate(); // == -0.5
Пример использования констант
Expression e = new Expression("a+b"); // a и b будут иметь значения null
e.getConstants().put("a", 3);
e.getConstants().put("b", 4);
double res = e.evaluate(); // == 7
Получение списка констант:
Set<String> names = e.getConstants().names(); //набор имён констант из выражения
Set<Map.Entry<String, Double>> entries = e.getConstants().entrySet(); //набор пар имя=значение
Collection<Double> values = e.getConstants().values(); //коллекция значений
for (String name : names) { //пример итерации по именам
System.out.println(name); //выведет имя
System.out.println(e.getConstants().get(name)); //выведет значение
}
Обработка ошибок
Класс Expression
при создании и вычислении выражения может
бросить исключение ExpressionException
. Определить, какая ошибка
произошла, можно, вызвав метод ExpressionException#getCode()
. Метод
вернёт enum-элемент типа ExpressionException.Code
. Коды ошибок бывают
следующие:
Ошибки в ходе анализа (лексические и синтаксические)
INVALID_CHARACTER
- неверный (неизвестный) символ;WRONG_NUMBER
- неверный формат числа;OPERATOR_WITHOUT_OPERAND
- не указан операнд для оператора (напр. "2+");RPAREN_UNEXPECTED
- неверное положение закрывающей скобки;LPAREN_MISSING
- не хватает открывающей скобки (закрывающая скобка без открывающей);UNEXPECTED_END
- неожиданный конец выражения;
Ошибки в ходе вычисления
SQRT_OF_NEG
- квадратный корень из отрицательного числа;FACT_OF_NEG
- факториал отрицательного числа;LOG_OF_NEG
- логарифм отрицательного числа;UNDEFINED_CONST
- неопределённая константа (не указано значение);DIV_BY_ZERO
- деление на ноль;
Объект ExpressionException
кроме сообщения и кода содержит информацию
о позиции ошибочной подстроки и о её длине
try {
Expression e = new Expression("26+*983"); // бросит исключение на символе '*'
} catch (ExpressionException e) {
System.out.println(e.getCode()); // выведет OPERATOR_WITHOUT_OPERAND
System.out.println(e.getMessage()); // выведет "Operator used without operand"
System.out.println(e.getPosition()); // выведет 3
System.out.println(e.getLength()); // выведет 1
System.out.println(e.getEndPosition()); // то же что и сумма позиции и длины
}
При попытке вычислить выражение, не назначив константам значения, метод
evaluate()
будет выбрасывать ошибку с кодом UNDEFINED_CONST
В случаях деления на ноль или получения факториала отрицательного числа, метод
evaluate()
не будет выбрасывать исключение, а будет возвращать Infinite
или NaN
. Чтобы "включить" исключение, необходимо вызвать метод evaluateStrict()
:
try {
Expression e = new Expression("10 / 0");
double d = e.evaluate(); // бесконечность
d = e.evaluateStrict();
} catch (ExpressionException e) {
System.out.println(e.getCode()); // DIV_BY_ZERO
}