Комментарии 60
Нам прямо предписывается использовать для обозначения унарного минуса любой свой придуманный символ. Давайте договоримся, что это будет тильда ~.
Унарный плюс не нужен, его можно просто найти и убрать, а унарный минус можно найти, убрать, и провести замену соответствующих последующих плюсов и минусов на противоположные знаки.
Опять же всё давно изобретено до нас, использовать мы будет классический алгоритм сортировочной станции. Просто распишем его максимально подробно и понятно.
унарный минус можно найти, убрать, и провести замену соответствующих последующих плюсов и минусов на противоположные знаки
Это как, приведите пример. Пожалуйста.
Например выражение
-2 - -2
Что мы должны сделать с унарным минусом в начале строки?
-2 - -2
? Предполагаю что в итоге будет - 2 + 2
.Кстати вариант про добавление эфемерного ноля, который тут упоминали в комментариях, тоже интересный, меньше мороки.
Любопытная конечно запись, и какой смысл вот так писать унарные минусы: -2 — -2
Что значит в чем смысл? Мы никогда не знаем, что придет нам на вход.
Вы не ответили на мой вопрос.
Вот ведь ответ:
- 2 + 2
. А если минус перед скобками, то это школьная арифметика, гуглить по словам: правило раскрытия скобок, перед которыми стоит знак минусЧто значит в чем смысл? Мы никогда не знаем, что придет нам на вход.
Для такого входные данные и нужно валидировать.
а унарный минус можно найти, убрать, и провести замену соответствующих последующих плюсов и минусов на противоположные знаки.
Еще раз: пожалуйста приведите алгоритм того, что вы написали
Странные у вас задачки для повышения. Это же типичная задача для первого-второго курса какого-нибудь универа.
Статья хотя и рассматривает тему, которая в интернете и различных учебниках раскрыта уже множество раз, но все же может кому-то пригодиться.
Вопрос в другом: зачем у вас в компании для повышения на следующий грейд решать какие-то выдуманные задачи, если процессу повышения предшествует как минимум полгода работы сотрудника? Разве его результатов за период не достаточно для принятия решения? В чем ценность того, что человек смог написать алгоритм калькулятора?
Надо убедиться что сотрудник способен хотя бы месяц заниматься подготовкой алгоритмов вместо работы и чтоб никто этого не замечал. Софт-скиллз!
Зумеры открыли для себя принцип работы калькуляторов БЗ-21, Б3-34 итд
Для красивого вычисления арифметического выражения в виде строки необходимо:Необходимо — слишком сильно сказано, скорее достаточно. Приведение к ОПЗ — это лишь один из вариантов, да и то, вместо формирования строки можно записывать числа во второй стек и все операции сразу же выполнять.
А ещё можно написать грамматику арифметических выражений и по ней разбирать выражение рекурсивным спуском или построить соответствующий грамматике МП-автомат.
Для красивого вычисления арифметического выражения в виде строки необходимо:
- Разобраться что такое Обратная польская запись, и почему она идеально подходит для машинных вычислений
- Привести арифметическое выражение к ОПЗ, и вычислить его
А я-то подумал, надо построить дерево выражений, а потом его вычислить...
Зачем делать кривой лексический анализатор, когда в язык PHP встроен www.php.net/manual/ru/book.tokenizer.php, прекрасно подходящий для разбора выражений?
Зачем эмулировать стеки массивами, когда в язык встроен www.php.net/manual/ru/class.splstack.php?
Для машины символ минус — это всегда оператор вычитания. Ни о каких унарных минусах машина не знает.Машина вообще не знает, что такое «минус». Она знает процессорный код команды вычитания и процессорный код команды изменения знака числа. Если данная процессорная архитектура не имеет команды изменения знака — компилятор подставит команду вычитания из нуля. Если имеет — компилятор воспользуется командой изменения знака.
Давайте рассмотрим простейший пример:C точки зрения машины — ничего не происходит. А с точки зрения генератора исполняемого кода будет вычислено константное выражение -2 и в генерируемую последовательность опкодов будет записана единственная команда: запись значения константы в переменную.
$a = -2
Что происходит в данном примере, с точки зрения машины?
<?php
$tokens = token_get_all("<?php 2+2*2;");
foreach ($tokens as $token) {
if (is_string($token)) {
print "STR: '{$token}'\n";
} else {
print token_name($token[0]) . ": '{$token[1]}', $token[2]\n";
}
}
/*
T_OPEN_TAG: '<?php ', 1
T_LNUMBER: '2', 1
STR: '+'
T_LNUMBER: '2', 1
STR: '*'
T_LNUMBER: '2', 1
STR: ';'
*/
с точки зрения генератора исполняемого кода будет вычислено константное выражение -2 и в генерируемую последовательность опкодов будет записана единственная команда: запись значения константы в переменную
Из моего окружения никто не смог объяснить почему интерпретатор php всегда неверно считает выражение:
<?php
echo -2 ** 2;
Объясните, пожалуйста, что такого в этом выражении, что -2 не вычисляется? Мне действительно интересно. Заранее спасибо.
"Из моего окружения никто не смог объяснить"
Если окружение с этим самым php не связано — это норма. Иначе даже и не знаю, как.это прокомментировать О_о.
Как видите, возведение в степень имеет больший приоритет, чем унарный минус.
Соответственно, -2**2 = -(2**2) = -4.
<?php
echo -2 ** 2; // -4 неверно
echo PHP_EOL;
echo -2 ** -2; // -0.25 верно
echo PHP_EOL;
echo -2 * -2; // 4 верно
echo PHP_EOL;
echo -2 / -2; // 1 верно
echo PHP_EOL;
-2 ** 2 = — (2 ** 2) = -4
-2 ** -2 = — (2 ** (-2)) == -0.25
Или вы хотите спросить, почему во втором случае второй унарный минус считается раньше возведения в степень? Потому что операция возведения считается справа налево.
-2 ** 2
Это я к чему? Самым простым решением для задачи
вычислить выражение из строки
будет:1. Провалидировать строку, и если выражение верное
2. Создать на лету php файл, записать в него выражение, и через exec получить результат вычисления
И не надо заморачиваться с алгоритмом.
Но:
1. Это неинтересно :)
2. Результат может быть неверным (-2 ** 2)
В любом случае php интерпретатор неверно высчитывает выражение -2 ** 2Верно считает. Не так, как вы представляли себе, но верно. Ещё в школе нас учили, что если основание степени отрицательное число, то при записи его всегда берут в скобки (-2)2.
(-2) ** 2 = 4
-2 ** 2 = -(2 ** 2) = -4
Вы точно уверены, что все манагеры напишут (-2) ^ 2?
Или они напишут -2 ^ 2?
Ни то, ни другое, потому что это не надо для вычисления стоимости.
При разработке такого калькулятора задача как раз в том, чтобы нельзя было ошибиться или ввести неоднозначное выражение.
Если, это верное арифметическое выражение, то считаем.
Иначе выкидываем исключение.
Выражение
-2 ** 2
априори считается верным. Выражение
(-2) ** 2
тоже вернымВ первом случае php посчитает неверно. Во втором — верно. Кто неправ?
Какое-то непонимание. Я фиг его знает, что прилетит снаружи.
В "калькуляторе вычисления стоимости металлических дверей"? Почему?
В первом случае php посчитает неверно.
Почему неверно-то?
Кто неправ?
Права спецификация, в которой указано, как такие случаи должны обрабатываться.
-2 ^ 2
Какой процент пользователей поставят её в скобки?
(-2) ^ 2
https://math.stackexchange.com/q/1299236/694842
Поучительное чтение.
Ну и да.
https://en.wikipedia.org/wiki/Order_of_operations#Unary_minus_sign
In written or printed mathematics, the expression −3^2 is interpreted to mean −(3^2) = − 9
если мы возводим отрицательное число в какую-либо степень, то мы должны заключить данный операнд в скобки
Ну вы даёте…
-2**2
0-2**2
Это одно и то же или нет?
Ок, полностью абстрагируемся от внешнего мира [...] Какой процент пользователей поставят её в скобки?
Пользователи — это и есть внешний мир. Вы либо абстрагируетесь, либо нет.
Какое-то непонимание. Я фиг его знает, что прилетит снаружи.Калькулятор вычисления стоимости металлических дверей, пластиковых окон, теплиц, и т.д., и т.п., никакого отношения к вычислению арифметического выражения в строке не имеет.
В таком калькуляторе вам приходит набор параметров двери — модель полотна, высота, ширина, модель замка, модели личинок, модель ручек, тип петель, наличие и типы декоративных элементов. Вам остаётся только провести калькуляцию по этим параметрам и выдать результат.
>> -2 ** 2
! Uncaught SyntaxError: unparenthesized unary expression can't appear on the left-hand side of '**'
Python тоже, кстати:
>>> -2 ** 2
-4
php > echo -(2 * -2);
4
php > echo (-2) * -2;
4
php > echo -(2 / -2);
1
php > echo (-2) / -2;
1
www.php.net/manual/ru/language.operators.precedence.php
В PHP единая таблица приоритетов для унарных и бинарных операций. И приоритет бинарной операции может быть выше приоритета унарной — как и произошло с возведением в степень.
Да, тем, кто привык к безусловной приоритетности унарных операций, ломает шаблон.
Алгоритм вычисления арифметического выражения в виде строки