fixfix
2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему На страницу 1, 2, 3, 4, 5, 6  След.
 
 Задача по ссылке от Munin
Сообщение22.02.2013, 14:35 


05/09/12
2587
В соседней теме участник Munin предложил (правда, не всем желающим, а ТС) следующую задачку http://atpp.vstu.edu.ru/cgi-bin/arh_pro ... id_prb=898
Однако, мне она показалась достаточно интересной - относительно простой, понятной, годящейся для начала и позволяющей потренироваться в устойчивости к некорректным входным данным. Вот я и взял и написал программку её решения (на языке 1С7.7 :D , мне так было проще, но это не принципиально, код приводится в теге оффтопика).

(Оффтоп)

Хотелось бы обсудить:
1) алгоритмические моменты
2) протестировать реакцию на разнообразно-некорректные входные данные
3) протестировать правильность вычислений (могу написать парсер выходного языка и вычисление значения выражений со случайными входными аргументами, и сравнить его с вычислением значения из исходной строки)
Для пунктов 2 и 3 можно предлагать навороченные строки в качестве исходных данных, буду выдавать результат.

 Профиль  
                  
 
 Re: Задача по ссылке от Munin
Сообщение22.02.2013, 15:23 
Заслуженный участник
Аватара пользователя


06/10/08
6422
Если меня не глючит, будет неправильно работать на строке "a-b-c" ( будет выдавать SUB(a,SUB(b,c)), а надо SUB(SUB(a, b), c) )
Также проверьте "a+b*", но тут зависит от поведения функции Сред, которого я не знаю.

(Оффтоп)


 Профиль  
                  
 
 Re: Задача по ссылке от Munin
Сообщение22.02.2013, 15:37 


05/09/12
2587
1) a-b-c перевод sub(A, sub(B,C)) - как вы и предполагали :-) Но тут немного философский вопрос, правильно это или нет. Если, например, явно указать порядок скобками, то получается (a-b)-c перевод sub( sub(A,B),C). А если явно не указывать, то я позволил себе более удобный мне порядок. Во всяком случае, требование автора задачи "Операнды должны идти в том же порядке, что и во входном выражении." не нарушается. Я похоже сильно ошибся и сделал неправильно! :oops: Эта моя алгоритмическая ошибка делает некорректным весь алгоритм... Ладно, доработаем...

2) a+b* перевод add(A, mul(B,)) - явная ошибка, спасибо вам, буду совершенствовать устойчивость. Я еще сам нашел, что +++ перевод add(+,+) - тоже буду дорабатывать :-) Я пока выложил в каком-то смысле "сырой" код - работающий, но не стопроцентно отрабатывающий некорректные данные. Доработаю, и если будет интерес - выложу код. Но алгоритмически он останется тот же самый, только будут дополнительные проверки и выставление флага ошибки при определенных ситуациях. Найденная выше ошибка автоматически аннулирует это высказывание...

(Оффтоп)


 Профиль  
                  
 
 Re: Задача по ссылке от Munin
Сообщение22.02.2013, 15:44 
Заслуженный участник
Аватара пользователя


06/10/08
6422

(Оффтоп)


 Профиль  
                  
 
 Re: Задача по ссылке от Munin
Сообщение22.02.2013, 15:50 


05/09/12
2587
Вы, возможно, будете смеяться, но если мой алгоритм будет выдавать a-b-c перевод sub(A, add(B,C)), то это будет считаться правильным решением задачи? :lol:

 Профиль  
                  
 
 Re: Задача по ссылке от Munin
Сообщение22.02.2013, 16:07 
Заслуженный участник
Аватара пользователя


06/10/08
6422
Цитата:
Выражения языка L записываются по обычным правилам [...]
По обычным правилам a-b-c означает (a-b)-c, а не a-(b-c)

 Профиль  
                  
 
 Re: Задача по ссылке от Munin
Сообщение22.02.2013, 16:15 


05/09/12
2587
То что вы написали, бесспорно. И я уже наступил на эти грабли и испытал некоторое чувство стыда от этого :oops: Но мне кажется, вы могли иметь в виду a-b-c означает (a-b)-c, а не a-(b+c). Сейчас фактически я могу сделать 2 алгоритма - переводящие a-b-c в sub( sub(A,B),C) и в sub(A, add(B,C)). Конечно предпочтительнее первый, но второй как шуточный вариант я тоже наверное реализую :lol:

 Профиль  
                  
 
 Re: Задача по ссылке от Munin
Сообщение22.02.2013, 16:21 
Заслуженный участник
Аватара пользователя


06/10/08
6422
Ой, извините. Не заметил.
Цитата:
[...]Получить запись этого выражения на языке F.[...]
На мой взляд, с ADD будет другое выражение, хотя и реализующее ту же функцию.

 Профиль  
                  
 
 Re: Задача по ссылке от Munin
Сообщение22.02.2013, 16:30 


05/09/12
2587
Изменил пробежку по строке - теперь бегу с конца в начало, соответственно порядок рекурсии меняется на противоположный и цепочка вычитаний раскручивается правильно. Но может ещё какая ошибка принципиальная наличествует. Корректность входных данных пока не отрабатывал, не до грибов :-) Код:

(Оффтоп)


 Профиль  
                  
 
 Re: Задача по ссылке от Munin
Сообщение22.02.2013, 16:42 
Заслуженный участник
Аватара пользователя


06/10/08
6422
Теперь с делениями та же проблема: "a/b/c" будет DIV(a, DIV(b,c))

 Профиль  
                  
 
 Re: Задача по ссылке от Munin
Сообщение22.02.2013, 16:46 


05/09/12
2587
Точно! Хотел с наскока, а придется все таки подумать... :-)

 Профиль  
                  
 
 Re: Задача по ссылке от Munin
Сообщение22.02.2013, 18:05 


05/09/12
2587
Релиз бета.3: бегу по строке слева направо, но перед пробежкой добавляю дополнительные скобки для определения порядка сложений-вычитаний текущего уровня рекурсии. Мне самому этот метод не кажется изящным, но вроде вышеупомянутые ошибки не допускает. В функцию передаются не указатели а сама строка по значению, внутри функции она ещё и изменяется - лишний кусочек ОЗУ не экономим. В функцию ДатьАргумент передается строка по ссылке, внутри отрезается. Код:

(Оффтоп)


 Профиль  
                  
 
 Re: Задача по ссылке от Munin
Сообщение22.02.2013, 19:03 
Заслуженный участник


27/04/09
28128

(Оффтоп)


 Профиль  
                  
 
 Re: Задача по ссылке от Munin
Сообщение22.02.2013, 23:19 


05/09/12
2587
Код:
alpha - beta - delta - gamma + phi/psi/ro/epsilon
ADD( SUB( SUB( SUB(alpha,beta),delta),gamma), DIV( DIV( DIV(phi,psi),ro),epsilon))
и отработка некорректных данных

 Профиль  
                  
 
 Re: Задача по ссылке от Munin
Сообщение23.02.2013, 00:05 
Заслуженный участник
Аватара пользователя


06/10/08
6422
По условию операнды однобуквенные, но многобуквенные операнды - это усложнение задачи, так что ок :)
Кстати, мой вариант (Haskell, quick and dirty, естественно без использования готовых парсеров)
код: [ скачать ] [ спрятать ] [ выделить ] [ развернуть ]
Используется синтаксис Haskell
module Main where

import Data.Char
import Control.Applicative
import Control.Monad
import Control.Arrow

splitOn :: (a -> Bool) -> [a] -> ([[a]], [a])
splitOn p xs =
  let
    (prefix, rest) = break p xs
  in
    if null rest
      then ([prefix], [])
      else (prefix:) *** (head rest :) $ (splitOn p $ tail rest)

type Marked = (Char, Integer)
data Tree = Leaf Char | Branch Char Tree Tree
type Parser = [Marked] -> Maybe Tree

instance Show Tree where
  show (Leaf c) = c:[]
  show (Branch c l r) = (op c) ++ "(" ++ (show l) ++ ", " ++ (show r) ++ ")"

isVar :: Char -> Bool
isVar c = isAlpha c && isAscii c

op :: Char -> String
op '+' = "ADD"
op '-' = "SUB"
op '*' = "MUL"
op '/' = "DIV"

mark :: String -> [Marked]
mark str = mark' (filter (/= ' ') str) 0 where
  mark' [] _ = []
  mark' ('(':rest) i = ('(', i):(mark' rest (i+1))
  mark' (')':rest) i = (')', i-1):(mark' rest (i-1))
  mark' (c:rest) i = (c, i):(mark' rest i)

parseLeftAssoc :: [Char] -> Parser -> Parser
parseLeftAssoc operators subparser str =
  let
    level = snd $ head str
    (summands, ops) = (reverse *** reverse) $ (map subparser *** map fst) $ splitOn ((flip elem operators) *** (==level) >>> uncurry (&&)) str
  in
    go summands ops
  where
    go [e] [] = e
    go [e] _ = Nothing
    go (e:es) (o:os) = Branch o <$> (go es os) <*> e

parseBracket :: Parser -> Parser
parseBracket _ [(c, n)] = guard (isVar c) >> (return $ Leaf c)
parseBracket subparser (('(', n):xs) = guard (last xs == (')', n)) >> (subparser $ init xs)
parseBracket _ _ = Nothing

parseExpr :: Parser
parseExpr = parseLeftAssoc "+-" $ parseLeftAssoc "*/" $ parseBracket parseExpr

parse :: String -> Maybe Tree
parse = parseExpr . mark

main :: IO ()
main = do
  string <- getLine
  let tree = parse string
  case tree of
    Nothing -> print "Error"
    Just t -> print t
 

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 89 ]  На страницу 1, 2, 3, 4, 5, 6  След.

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group