программистская задачка
Mar. 20th, 2018 07:22 pmКоллега недавно предложил следующее задание, которое мне понравилось в качестве разминки:
Написать код, который вычисляет значение числового выражения, использующего скобки и арифметические действия, используя только константное количество локальных переменных. На любом языке. Код должен печатать результат вычисления, или ошибку (можно неинформативную) в случае некорректного ввода.
На входе: строка типа "(2+2)*12" или 56-4*2 или -10^2 итд. Разрешаются скобки и операторы: унарные + и -, бинарные +,-,*,/,^ (возведение в степень). У бинарных операторов обычные уровни приоритета и левая ассоциация внутри уровня, т.е. 10-5-2 равно 3, а не 7. Разрешаются ненужные скобки "(3)". Если в вашем языке нет целочисленной степени, не надо ее имплементировать, можно обойти трюками (напр. в C/C++ перейти к плавающей точке, возвести в степень и округлить). Можно предположить, что все числа и результаты укладываются в размер целочисленного типа вашего языка, если есть такое ограничение. Запрещено использовать массивы, стеки, списки, динамически отведенную память непостоянного размера и другие способы иметь локально неограниченную память в контексте конкретного запуска конкретной функции. Ну и конечно пользоваться чем-то вроде eval() своего языка нельзя, нужно "честно" решить.
Я не утверждаю, что это какое-то особо глубокое или сложное задание, просто хороший способ тряхнуть стариной и элегантно организовать логику. Если вы хотите поучаствовать, присылайте код ссылками на https://pastebin.com/ или свой гитхаб или еще как угодно. Я добавлю ссылку на свое решение (на питоне) завтра вечером к этой записи.
P.S. Поясняю насчет рекурсии. Правила специально сформулированы так ("в контексте конкретного запуска конкретной функции"), что рекурсию МОЖНО использовать. Если вы можете обойтись без рекурсии (я специально не говорю, легко это или тяжело, можно или нельзя), то тоже хорошо, но и рекурсия разрешается.
Update: Спасибо за присланные решения, они все красивые и хорошие :) Мое решение: https://pastebin.com/J6mpMRb2 (исправлены два бага, спасибо комментаторам!).
Написать код, который вычисляет значение числового выражения, использующего скобки и арифметические действия, используя только константное количество локальных переменных. На любом языке. Код должен печатать результат вычисления, или ошибку (можно неинформативную) в случае некорректного ввода.
На входе: строка типа "(2+2)*12" или 56-4*2 или -10^2 итд. Разрешаются скобки и операторы: унарные + и -, бинарные +,-,*,/,^ (возведение в степень). У бинарных операторов обычные уровни приоритета и левая ассоциация внутри уровня, т.е. 10-5-2 равно 3, а не 7. Разрешаются ненужные скобки "(3)". Если в вашем языке нет целочисленной степени, не надо ее имплементировать, можно обойти трюками (напр. в C/C++ перейти к плавающей точке, возвести в степень и округлить). Можно предположить, что все числа и результаты укладываются в размер целочисленного типа вашего языка, если есть такое ограничение. Запрещено использовать массивы, стеки, списки, динамически отведенную память непостоянного размера и другие способы иметь локально неограниченную память в контексте конкретного запуска конкретной функции. Ну и конечно пользоваться чем-то вроде eval() своего языка нельзя, нужно "честно" решить.
Я не утверждаю, что это какое-то особо глубокое или сложное задание, просто хороший способ тряхнуть стариной и элегантно организовать логику. Если вы хотите поучаствовать, присылайте код ссылками на https://pastebin.com/ или свой гитхаб или еще как угодно. Я добавлю ссылку на свое решение (на питоне) завтра вечером к этой записи.
P.S. Поясняю насчет рекурсии. Правила специально сформулированы так ("в контексте конкретного запуска конкретной функции"), что рекурсию МОЖНО использовать. Если вы можете обойтись без рекурсии (я специально не говорю, легко это или тяжело, можно или нельзя), то тоже хорошо, но и рекурсия разрешается.
Update: Спасибо за присланные решения, они все красивые и хорошие :) Мое решение: https://pastebin.com/J6mpMRb2 (исправлены два бага, спасибо комментаторам!).
no subject
Date: 2018-03-20 05:42 pm (UTC)no subject
Date: 2018-03-20 05:44 pm (UTC)no subject
Date: 2018-03-20 05:46 pm (UTC)no subject
Date: 2018-03-20 05:49 pm (UTC)no subject
Date: 2018-03-20 05:53 pm (UTC)no subject
Date: 2018-03-20 05:58 pm (UTC)Короче говоря, можно было просто попросить написать рекурсивный парсер.
no subject
Date: 2018-03-20 06:13 pm (UTC)Более того, это проще, чем на самом деле использовать свой стек, без рекурсии.
no subject
Date: 2018-03-20 06:18 pm (UTC)no subject
Date: 2018-03-20 06:46 pm (UTC)говорит: а рекурсивно можно функции вызывать? )
no subject
Date: 2018-03-20 06:51 pm (UTC)no subject
Date: 2018-03-20 07:04 pm (UTC)no subject
Date: 2018-03-20 07:16 pm (UTC)no subject
Date: 2018-03-20 07:22 pm (UTC)no subject
Date: 2018-03-20 07:24 pm (UTC)no subject
Date: 2018-03-20 07:25 pm (UTC)no subject
Date: 2018-03-20 07:31 pm (UTC)Кроме того, то, что задачу нельзя решить *без* рекурсии, не столь уж тривиально (да даже и неверно для некоторых видов ухищрений). Например, возьмем более простую задачу проверки правильной вложенности скобок, и более ничего. Понятно, что ее легко решить без рекурсии, просто держа в счетчике число открытых скобок. Формально говоря, это нерегулярный язык и конечный автомат его не может решить, но для решения конкретной задачи "написать код, который проверяет скобки в реальной строке реалистичной длины" это оказывается нерелевантно!
Может, и для более сложной задачи "вычислить выражение" найдется такое решение? А может, нет? Это то, о чем мне хотелось бы, чтобы решатель подумал сам, и решил для себя сам, а не получил от меня на тарелочке.
no subject
Date: 2018-03-20 07:33 pm (UTC)no subject
Date: 2018-03-20 07:34 pm (UTC)no subject
Date: 2018-03-20 07:44 pm (UTC)А если свой стек писать, то гораздо сложнее получится, состояние еще туда записывать, ну его :)
no subject
Date: 2018-03-20 08:09 pm (UTC)no subject
Date: 2018-03-20 08:19 pm (UTC)no subject
Date: 2018-03-20 09:08 pm (UTC)no subject
Date: 2018-03-20 09:19 pm (UTC)no subject
Date: 2018-03-20 09:34 pm (UTC)no subject
Date: 2018-03-20 09:36 pm (UTC)