|
Due to the numerous midterms and the vast amount of the homework in that period the Romanian CID (Country Information Day) was not held on its original date, 4th of November 2010.
But no fear ! After that shaky start, the Romanians are back to show everyone what they're made of. Wisely reprogramming the event before the finals period and right after the Mercator Christmas Decoration, they regrouped and are now plotting to make a CID that will baffle everyone, that will take place on the 9th of December. If you happen to pass late in the evening through our common room, you will have a good change to take a peek of what will be happening that day, as they are often there either dancing their dances, plotting their planes or just simply brainstorming.
Meanwhile, you can check their previous 2 CID's, one better than the other :
The 2006 one
The 2004 one

(** Stefan Mirea **)
(**
zxdszNOTE: this is a general equation parser function without paranthesis, not only a 2nd degree polinomial one. **)
exception Bonk; exception BonkInvalidInput; exception BonkEmptyString; exception BonkNotReal; exception BonkEmptyList; exception BonkNeedGreaterThanZero; exception BonkParanthesisMissmatch;
(** The maximum element in a list **) fun max ([]) = raise BonkEmptyList | max (a::[]) = a | max (a::b::t) = if a > b then max (a::t) else max (b::t);
(** The minimum element in a list **) fun min ([]) = raise BonkEmptyList | min (a::[]) = a | min (a::b::t) = if a < b then min (a::t) else min (b::t);
(** repl(list, index, length, replaceWith) -replaces "length" characters from "list" starting after the element at position "index" with "replaceWith" **) fun repl ([], _, _,_ ) = [] | repl(h::t, 0, 0, l) = (h :: l) @ t | repl(a::b::t, 0, n, l) = repl (a::t, 0, n-1, l) | repl(h::t, p, n, l) = [h] @ repl (t, p-1, n, l);
(** Same as above, only works with strings **) fun replStr (l1, p, n, l2) = implode ( repl(explode l1, p, n, explode l2) );
(** Returns a list sliced in 2 at position n as a pair (a, b) **) fun sliceAt (a, b, 0) = (b, a) | sliceAt (h::t, b, n) = sliceAt (t, b @ [h], n-1) | sliceAt (_, _, _) = ([], []);
(** Returns a string sliced in 2 at position n as a pair (a, b) **) fun sliceStrAt (str, n) = let val (a, b) = sliceAt ( explode str, [], n ); in (implode a, implode b) end;
(** Pos of an element in a list **) fun indexOf ([], x, p) = ~1 | indexOf (h::t, x, p) = if h = x then p else indexOf (t, x, p+1);
(** Pos of an element in a string **) fun indexOfStr (str, x) = indexOf(explode str, x, 0);
(** Pos of an element in a string starting from offset "off" **) fun indexOfStrOffset (str, x, off) = let val (a, b) = sliceStrAt(str, off) val p = indexOfStr(b, x) in if p < 0 then ~1 else size a + p end;
(** Pos of the last of that kind of elements in a list **) fun lastIndexOf([], x, p, l) = l | lastIndexOf(h::t, x, p, l) = if h = x then lastIndexOf(t, x, p+1, p) else lastIndexOf(t, x, p+1, l);
(** Pos of the last of that kind of elements in the string **) fun lastIndexOfStr (str, x) = lastIndexOf(explode str, x, 0, ~1);
(** Replace all occurences of "x" with "y" in a string **) fun replaceAll (str, x, y) = let val p = indexOfStr(str, x) in if p > ~1 then let val s = replStr(" " ^ str, p, 1, y) in replaceAll( substring(s, 1, (size s)-1 ), x, y) end else str end;
(** Used map the function bellow so negative values won't be considered **) fun greaterThanZero x = if x <= 0 then 69696969 else x; (** Gets the first token in a string **) fun getFirst str = let val p = min( map greaterThanZero [indexOfStr(str, #"+"), indexOfStr(str, #"-"), indexOfStr(str, #"*"), indexOfStr(str, #"/")] ) in if p > ~1 andalso p <> 69696969 then sliceStrAt(str, p) else (str, "") end;
(** Gets the last token in a string **) fun getLast str = let val p = max( [lastIndexOfStr(str, #"+"), lastIndexOfStr(str, #"-"), lastIndexOfStr(str, #"*"), lastIndexOfStr(str, #"/")] ) in if p > ~1 then sliceStrAt(str, p+1) else ("", str) end;
(** Takes a string, returns a real or bonks an exception **) fun toReal x = let fun isReal NONE = false | isReal (SOME x) = true; in if isReal(Real.fromString(x)) then let val SOME y = Real.fromString(x) in y end else raise BonkNotReal end;
(** Simple operations evaluator; It evaluates only 1 operation at a time Example algorithm: input: ( 2+3*5+4*2+1, op* ) (this will get tokenized in the main function) -> ["2+3", "5+4", "2+1"] It iterates the list once, taking the first 2 elements. The last token from each element and the first token from the second element are added as arguments to the operation function and the result is concatenated. Output: "2+15.0+8.0+1" **) fun ev (e1::[], _) = e1 | ev (e1::e2::e3, f) = let val (h, a) = getLast e1 val (b, t) = getFirst e2 val str = h ^ ev( (Real.toString( f( toReal a, toReal b ) ) ^ t ):: e3, f ) in str end | ev(_, _) = "";
(** Functions used for tokenizing by operators **) fun getSum #"+" = true | getSum _ = false; fun getDifference #"-" = true | getDifference _ = false; fun getMultiplication #"*" = true | getMultiplication _ = false; fun getDivision #"/" = true | getDivision _ = false;
(** THE Function for evaluating polinomial equations It takes each of the 4 operations and applies the ev() function with each of them, prioritizing by the order: / * - + and outputs the result as a Real **) fun evPoli(str, x:real) = let val s = replaceAll(str, #"x", Real.toString x) val step1 = ev(String.tokens getDivision s, op/) val step2 = ev(String.tokens getMultiplication step1, op* ) val step3 = ev(String.tokens getDifference step2, op-) val step4 = ev(String.tokens getSum step3, op+) in toReal step4 end;
(** Math functions with embeded exceptions **) fun sin x = Math.sin x; fun cos x = Math.cos x; fun log x = if x <= 0.0 then raise BonkNeedGreaterThanZero else Math.ln x; fun exp x = Math.exp x;
(** In order to get this done quickly and not have to implement an indexOf String*String->int, i will simply rename all the functions with their first character. i.e.: "sin(x)"->"S(x)" **) (** We a list made from our functions and their notations **) val functions = [ (#"S", sin), (#"C", cos), (#"L", log), (#"E", exp) ];
(** The main function string parser. It gets the arguments of every function and applies the custom math functions above It is also modular, meaning that by simply adding a abreviation and a function, as a pair, to the "functions" list above you can register a new function to the parser **) fun evFn(str, [], x:real) = evPoli(str, x) | evFn(str, h::t, x:real) = let val (s, f) = h val p = indexOfStr(str, s) in if p > ~1 then let val pos = indexOfStrOffset(str, #")", p + 1 + 1) (** normally it should be: "p + (size s) + 1" **) in if pos > ~1 then let val argStr = replaceAll( substring(str, p + 1 + 1, pos - p - 2), #"x", Real.toString x) val newStr = substring(str, 0, p) ^ Real.toString( f( evFn( argStr, h::t, x) ) ) ^ substring(str, pos+1, (size str) - pos-1) in evFn(newStr, h::t, x) end else raise BonkParanthesisMissmatch end else evFn(str, t, x) end;
(** Checks if the first list is made only with the elements of the second string **) fun hasOnly([], str) = true | hasOnly(_, "") = false | hasOnly(a::A, str) = (Char.contains str a) andalso hasOnly(A, str);
(** Checks if the first string is made only with the elements of the second string **) fun hasOnlyStr(str, l) = hasOnly(explode str, l);
(** THE function. Checks if the string is valid and if it is, evaluates it **) fun evaluateexp ("", _) = raise BonkEmptyString | evaluateexp (str, x:real) = if hasOnlyStr(str, "0123456789xSCEL.+-*/()") then evFn( replaceAll(str, #"x", Real.toString x), functions, x) else raise BonkInvalidInput;
|