Last active
February 22, 2017 06:32
-
-
Save at1as/6db64093cc0efc14701135ce003458ca to your computer and use it in GitHub Desktop.
Assignment #1 Functional Programming in Erlang
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-module(bits). | |
-export([bits/1, bitsNoTailRecursion/1, startTests/0]). | |
%% Functional Programming in Erlang | |
%% Kent University | |
%% 21 February 2017 | |
%% Exercise 1 : Summing the Bits | |
%% | |
%% Convert String of Binary representation to List of Strings | |
%% (String) -> List(String) | |
%% | |
%% Ex. "1101" -> ["1", "1", "0", "1"] | |
%% | |
%% Limitations : "string:substr(S, 2, 10000)" is very lazy. It assumes no input over 10000 characters | |
%% This conversion is quite convoluted. Surely there is a better way to do this | |
%% | |
%% Note: | |
%% stringToList(string:substr(S, 2, 10000), Xs ++ [string:substr(S, 1, 1)]) | |
%% | |
%% Will take the input string S, take off the first letter, append it to the output list and call itself | |
%% | |
%% (S = "hello", Xs = []) -> (S = "ello", Xs = ["h"]) -> (S = "llo", Xs = ["h", "e"]) -> etc | |
%% | |
%% In this case, however, all digits will be "1" or "0" as all inputs only contain combinations of 1's and 0's | |
%% | |
stringToList(S) -> | |
stringToList(S, []). | |
stringToList("", X) -> | |
X; | |
stringToList(S, []) -> | |
stringToList(string:substr(S, 2, 10000), [string:substr(S, 1, 1)]); | |
stringToList(S, Xs) -> | |
stringToList(string:substr(S, 2, 10000), Xs ++ [string:substr(S, 1, 1)]). | |
%% | |
%% Sum the number of Binary 1's for a given base 10 integer | |
%% (Integer) -> Integer | |
%% This Method with Tail Recursion (which is usually preferred as it is faster and easier on memory) | |
%% | |
%% Ex. 7 -> 3 (0111) | |
%% | |
%% Note: | |
%% integer_to_list(9, 2) -> "1001" | |
%% stringToList("111") -> ["1", "0", "0", "1"] | |
%% | |
bits(X) -> | |
sumOfBits(stringToList(integer_to_list(X, 2))). | |
sumOfBits([X|Xs]) -> | |
sumOfBits([X|Xs], 0). | |
sumOfBits([], S) -> | |
S; | |
sumOfBits([X|Xs], S) -> | |
case X == "1" of %% stringToList ensures results come back as "1" in string format | |
true -> | |
sumOfBits(Xs, S + 1); | |
false -> | |
sumOfBits(Xs, S) | |
end. | |
%% | |
%% Sum the number of Binary 1's for a given base 10 integer | |
%% (Integer) -> Integer | |
%% Solution without Tail Recursion | |
%% | |
%% Ex. 3 -> 2 (011) | |
%% | |
%% Note: | |
%% integer_to_list(9, 2) -> "1001" | |
%% stringToList("111") -> ["1", "0", "0", "1"] | |
%% | |
bitsNoTailRecursion(X) -> | |
sumOfBitsR(stringToList(integer_to_list(X, 2))). | |
sumOfBitsR([]) -> | |
0; | |
sumOfBitsR([X|Xs]) -> | |
case X == "1" of %% stringToList ensures results come back as "1" in string format | |
true -> | |
1 + sumOfBitsR(Xs); | |
false -> | |
sumOfBitsR(Xs) | |
end. | |
%% | |
%% Tests | |
%% | |
startTests() -> | |
%% Functions using tail recursion | |
io:fwrite("Should be 3 (input 7) : ~w\n", [bits:bits(7)]), | |
io:fwrite("Should be 1 (input 1) : ~w\n", [bits:bits(1)]), | |
io:fwrite("Should be 2 (input 3) : ~w\n", [bits:bits(3)]), | |
io:fwrite("Should be 1 (input 8) : ~w\n", [bits:bits(8)]), | |
io:fwrite("Should be 1 (input 64) : ~w\n", [bits:bits(64)]), | |
%% Functions without tail recursion | |
io:fwrite("Should be 3 (input 7) : ~w\n", [bits:bitsNoTailRecursion(7)]), | |
io:fwrite("Should be 1 (input 1) : ~w\n", [bits:bitsNoTailRecursion(1)]), | |
io:fwrite("Should be 2 (input 3) : ~w\n", [bits:bitsNoTailRecursion(3)]), | |
io:fwrite("Should be 1 (input 8) : ~w\n", [bits:bitsNoTailRecursion(8)]), | |
io:fwrite("Should be 1 (input 64) : ~w\n", [bits:bitsNoTailRecursion(64)]). | |
%% | |
%% OUPUT of startTests() | |
%% | |
%% 211> bits:startTests() | |
%% 211> . | |
%% Should be 3 (input 7) : 3 | |
%% Should be 1 (input 1) : 1 | |
%% Should be 2 (input 3) : 2 | |
%% Should be 1 (input 8) : 1 | |
%% Should be 1 (input 64) : 1 | |
%% Should be 3 (input 7) : 3 | |
%% Should be 1 (input 1) : 1 | |
%% Should be 2 (input 3) : 2 | |
%% Should be 1 (input 8) : 1 | |
%% Should be 1 (input 64) : 1 | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-module(shapes). | |
-export([perimeter/1, area/1, enclose/1, startTests/0]). | |
% For Functional Programming in Erlang | |
% Kent University | |
% 21 February 2017 | |
%% | |
%% Triangle Inequality Theorem defines valid Triangles | |
%% | |
validTriangle({A, B, C}) when A + B > C, B + C > A, A + C > B -> | |
true; | |
validTriangle({_A, _B, _C}) -> | |
false. | |
%% | |
%% Perimeter Formula for Square, Rectangle, Circle and Triangle | |
%% | |
perimeter({square, X}) when is_integer(X) or is_float(X) -> | |
{ok, X * 4}; | |
perimeter({rectangle, X, Y}) when (is_integer(X) or is_float(X)) and (is_integer(Y) or is_float(Y)) -> | |
{ok, X * 2 + Y * 2}; | |
perimeter({circle, R}) when is_integer(R) or is_float(R) -> | |
{ok, 2 * math:pi() * R}; | |
perimeter({triangle, A, B, C}) -> | |
case validTriangle({A, B, C}) of | |
true -> | |
{ok, A + B + C}; | |
false -> | |
{error, -1} | |
end. | |
%% | |
%% Area Formula for Square, Rectangle, Circle and Triangle | |
%% | |
area({square, X}) when is_integer(X) or is_float(X) -> | |
{ok, X * X}; | |
area({rectangle, X, Y}) when (is_integer(X) or is_float(X)) and (is_integer(Y) or is_float(Y)) -> | |
{ok, X * Y}; | |
area({circle, R}) when is_integer(R) or is_float(R) -> | |
{ok, math:pi() * R * R}; | |
area({triangle, A, B, C}) -> %% validTriangle/3 will guard against non number inputs | |
case validTriangle({A, B, C}) of | |
true -> %% See Heron's Formula. This is valid for all triangle types | |
S = (A+B+C)/2, | |
{ok, math:sqrt(S*(S-A)*(S-B)*(S-C))}; | |
false -> | |
{error, -1} | |
end. | |
%% | |
%% Enclosing Box Formula for Square, Rectangle, Circle and Triangle | |
%% | |
enclose({square, X}) when is_integer(X) or is_float(X) -> | |
{ok, {0, 0}, {0, X}, {X, 0}, {X, X}}; | |
enclose({rectangle, X, Y}) -> | |
{ok, {0, 0}, {0, X}, {Y, 0}, {Y,X}}; | |
enclose({circle, R}) when is_integer(R) or is_float(R) -> | |
{ok, {0, 0}, {0, 2 * R}, {2 * R, 0}, {2 * R, 2 * R}}; | |
enclose({triangle, A, B, C}) -> %% validTriangle/3 will guard against non number inputs | |
case validTriangle({A, B, C}) of | |
true -> | |
S = (A+B+C)/2, %% Heron's formula also yields triangle height given dimensions | |
H = (2/C) * math:sqrt(S*(S-A)*(S-B)*(S-C)), | |
{ok, {0, 0}, {0, H}, {C, 0}, {C, H}}; | |
false -> | |
{error, -1} | |
end. | |
%% | |
%% TESTS | |
%% | |
printTest(TESTNAME, EXPECTED, OUTPUT) -> | |
{ok, R} = OUTPUT, | |
io:fwrite("~s should be \t\t ~w -> ~w\n", [TESTNAME, EXPECTED, R]). | |
printTest(TESTNAME, EXPECTED, OUTPUT, _TYPE) -> | |
{ok, A, B, C, D} = OUTPUT, | |
io:fwrite("~s should be \t\t ~w -> ~w,~w,~w,~w\n", [TESTNAME, EXPECTED, A, B, C, D]). | |
startTests() -> | |
%% Perimeter Tests | |
printTest("Perimeter : Square : Integer ", 8, perimeter({square, 2})), | |
printTest("Perimeter : Square : Float", 16.0, perimeter({square, 4.0})), | |
printTest("Perimeter : Rectangle : Integer ", 14, perimeter({rectangle, 3, 4})), | |
printTest("Perimeter : Rectangle : Float", 20.0, perimeter({rectangle, 9.0, 1.0})), | |
printTest("Perimeter : Circle : Integer ", 2 * math:pi()*10, perimeter({circle, 10})), | |
printTest("Perimeter : Circle : Float", 2 * math:pi()*20.0, perimeter({circle, 20.0})), | |
printTest("Perimeter : Triangle : Integer ", 31, perimeter({triangle, 15, 9, 7})), | |
printTest("Perimeter : Triangle : Float ", 31.0, perimeter({triangle, 15.0, 9.0, 7.0})), | |
io:fwrite("\n"), | |
%% Area Test | |
printTest("Area : Square : Integer ", 4, area({square, 2})), | |
printTest("Area : Square : Float", 25.0, area({square, 5.0})), | |
printTest("Area : Rectangle : Integer ", 12, area({rectangle, 3, 4})), | |
printTest("Area : Rectangle : Float", 9.0, area({rectangle, 9.0, 1.0})), | |
printTest("Area : Circle : Integer ", math:pi()*10*10, area({circle, 10})), | |
printTest("Area : Circle : Float", math:pi()*20.0*20.0, area({circle, 20.0})), | |
printTest("Area : Triangle : Integer ", 20.69269194667528, area({triangle, 15, 9, 7})), | |
printTest("Area : Triangle : Float ", 20.69269194667528, area({triangle, 15.0, 9.0, 7.0})), | |
io:fwrite("\n"), | |
%% Enclosing Square Test | |
printTest("Enclosing Square : Square : Integer ", '{0,0},{0,2},{2,0},{2,2}', enclose({square, 2}), "Enclosing"), | |
printTest("Enclosing Square : Square : Float", '{0,0},{0,5.0},{5.0,0},{5.0,5.0}', enclose({square, 5.0}), "Enclosing"), | |
printTest("Enclosing Square : Rectangle : Integer ", '{0,0},{0,3},{4,0},{4,3}', enclose({rectangle, 3, 4}), "Enclosing"), | |
printTest("Enclosing Square : Rectangle : Float", '{0,0},{0,9.0},{1.0,0},{1.0,9.0}', enclose({rectangle, 9.0, 1.0}), "Enclosing"), | |
printTest("Enclosing Square : Circle : Integer ", '{0,0},{0,20},{20,0},{20,20}', enclose({circle, 10}), "Enclosing"), | |
printTest("Enclosing Square : Circle : Float", '{0,0},{0,40.0},{40.0,0},{40.0,40.0}', enclose({circle, 20.0}), "Enclosing"), | |
printTest("Enclosing Square : Triangle : Integer ", '{0,0},{0,5.912197699050079},{7,0},{7,5.912197699050079}', enclose({triangle, 15, 9, 7}), "Enclosing"), | |
printTest("Enclosing Square : Triangle : Float ", '{0,0},{0,5.912197699050079},{7,0},{7,5.912197699050079}', enclose({triangle, 15.0, 9.0, 7.0}), "Enclosing"). | |
%% OUTPUT FROM TESTS | |
%% 197> shapes:startTests(). | |
%% Perimeter : Square : Integer should be 8 -> 8 | |
%% Perimeter : Square : Float should be 16.0 -> 16.0 | |
%% Perimeter : Rectangle : Integer should be 14 -> 14 | |
%% Perimeter : Rectangle : Float should be 20.0 -> 20.0 | |
%% Perimeter : Circle : Integer should be 62.83185307179586 -> 62.83185307179586 | |
%% Perimeter : Circle : Float should be 125.66370614359172 -> 125.66370614359172 | |
%% Perimeter : Triangle : Integer should be 15 -> 31 | |
%% Perimeter : Triangle : Float should be 15.0 -> 31.0 | |
%% Area : Square : Integer should be 4 -> 4 | |
%% Area : Square : Float should be 25.0 -> 25.0 | |
%% Area : Rectangle : Integer should be 12 -> 12 | |
%% Area : Rectangle : Float should be 9.0 -> 9.0 | |
%% Area : Circle : Integer should be 314.1592653589793 -> 314.1592653589793 | |
%% Area : Circle : Float should be 1256.6370614359173 -> 1256.6370614359173 | |
%% Area : Triangle : Integer should be 20.69269194667528 -> 20.69269194667528 | |
%% Area : Triangle : Float should be 20.69269194667528 -> 20.69269194667528 | |
%% Enclosing Square : Square : Integer should be '{0,0},{0,2},{2,0},{2,2}' -> {0,0},{0,2},{2,0},{2,2} | |
%% Enclosing Square : Square : Float should be '{0,0},{0,5.0},{5.0,0},{5.0,5.0}' -> {0,0},{0,5.0},{5.0,0},{5.0,5.0} | |
%% Enclosing Square : Rectangle : Integer should be '{0,0},{0,3},{4,0},{4,3}' -> {0,0},{0,3},{4,0},{4,3} | |
%% Enclosing Square : Rectangle : Float should be '{0,0},{0,9.0},{1.0,0},{1.0,9.0}' -> {0,0},{0,9.0},{1.0,0},{1.0,9.0} | |
%% Enclosing Square : Circle : Integer should be '{0,0},{0,20},{20,0},{20,20}' -> {0,0},{0,20},{20,0},{20,20} | |
%% Enclosing Square : Circle : Float should be '{0,0},{0,40.0},{40.0,0},{40.0,40.0}' -> {0,0},{0,40.0},{40.0,0},{40.0,40.0} | |
%% Enclosing Square : Triangle : Integer should be '{0,0},{0,5.912197699050079},{7,0},{7,5.912197699050079}' -> {0,0},{0,5.912197699050079},{7,0},{7,5.912197699050079} | |
%% Enclosing Square : Triangle : Float should be '{0,0},{0,5.912197699050079},{7,0},{7,5.912197699050079}' -> {0,0},{0,5.912197699050079},{7.0,0},{7.0,5.912197699050079} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment