Created
March 4, 2017 08:10
-
-
Save mrc/eb78056fa0ae93b42efe16fbf0ccd3fa to your computer and use it in GitHub Desktop.
week 1 assignment from https://www.futurelearn.com/courses/functional-programming-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(assignment). | |
-export([area/1, perimeter/1, enclose/1, | |
testArea/0, testPerimeter/0, testEnclose/0, | |
bits/1, bitsDirect/1, bitsTailRecursive/1, | |
testBits/0, | |
testAll/0, allTestsPass/0]). | |
%% circle: {circle, Radius} | |
%% square: {square, Length} | |
%% rectangle: {rectangle, Length, Width} | |
%% triangle: {triangle, A, B, C} (triple of side lengths) | |
area({circle, R}) -> | |
math:pi()*R*R; | |
area({square, L}) -> | |
L*L; | |
area({rectangle, L, W}) -> | |
L*W; | |
area({triangle, A, B, C}) -> | |
S = (A+B+C) / 2, | |
math:sqrt(S * (S-A) * (S-B) * (S-C)). | |
perimeter({circle, R}) -> | |
2*math:pi()*R; | |
perimeter({square, L}) -> | |
L*4; | |
perimeter({rectangle, L, W}) -> | |
L*2 + W*2; | |
perimeter({triangle, A, B, C}) -> | |
A + B + C. | |
enclose({circle, R}) -> | |
{rectangle, R*2, R*2}; | |
enclose({square, L}) -> | |
{rectangle, L, L}; | |
enclose({rectangle, L, W}) -> | |
{rectangle, L, W}; | |
enclose({triangle, A, B, C}) -> | |
%% the bounding rectangle is as wide as one of the sides, and as | |
%% high as the height of the triangle if that side is considered | |
%% the base. | |
%% | |
%% for this calculation, the base (width) of the bounding | |
%% rectangle is parallel with C, so the height is the distance | |
%% between C and the point AB. | |
%% | |
%% theorum: no matter which side I use as the base, the area of | |
%% the bounding rectangle is the same, therefore the bounding | |
%% rectangle is the smallest possible no matter which side I use | |
%% as the base. | |
H = 2*(area({triangle, A, B, C}) / C), | |
{rectangle, H, C}. | |
almost(A, B) -> | |
Epsilon = 1.0e-5, | |
abs(A - B) < Epsilon. | |
testArea() -> | |
[almost(math:pi()*25, area({circle, 5})), | |
almost(25, area({square, 5})), | |
almost(30, area({rectangle, 5, 6})), | |
almost(6, area({triangle, 3, 4, 5}))]. | |
testPerimeter() -> | |
[almost(math:pi()*10, perimeter({circle, 5})), | |
almost(20, perimeter({square, 5})), | |
almost(22, perimeter({rectangle, 5, 6})), | |
almost(12, perimeter({triangle, 3, 4, 5}))]. | |
almostEquivalentRectangle(R1, R2) -> | |
almost(area(R1), area(R2)). | |
testEnclose() -> | |
[almostEquivalentRectangle({rectangle, 10, 10}, enclose({circle, 5})), | |
almostEquivalentRectangle({rectangle, 5, 5}, enclose({square, 5})), | |
almostEquivalentRectangle({rectangle, 5, 6}, enclose({rectangle, 5, 6})), | |
almostEquivalentRectangle({rectangle, 10, 10}, enclose({circle, 5})), | |
almostEquivalentRectangle({rectangle, 3, 4}, enclose({triangle, 3, 4, 5})), | |
almostEquivalentRectangle({rectangle, 3, 4}, enclose({triangle, 3, 5, 4})), | |
almostEquivalentRectangle({rectangle, 3, 4}, enclose({triangle, 4, 3, 5})), | |
almostEquivalentRectangle({rectangle, 3, 4}, enclose({triangle, 4, 5, 3})), | |
almostEquivalentRectangle({rectangle, 3, 4}, enclose({triangle, 5, 3, 4})), | |
almostEquivalentRectangle({rectangle, 3, 4}, enclose({triangle, 5, 4, 3}))]. | |
%% bits: direct recursion | |
bitsDirect(0) -> | |
0; | |
bitsDirect(1) -> | |
1; | |
bitsDirect(N) -> | |
B = N band 1, | |
B + bitsDirect(N bsr 1). | |
%% bits: tail recursion | |
bitsHelper(0, Acc) -> | |
Acc; | |
bitsHelper(1, Acc) -> | |
Acc + 1; | |
bitsHelper(N, Acc) -> | |
bitsHelper(N bsr 1, Acc + N band 1). | |
bitsTailRecursive(N) -> | |
bitsHelper(N, 0). | |
%% assignment said "define bits/1". | |
%% | |
%% commentary: the tail recursive function is more efficient because | |
%% it doesn't use the stack to build the result, but the direct | |
%% function is easier to read (and was easier to construct). | |
bits(N) -> | |
bitsTailRecursive(N). | |
testBits() -> | |
[3 == bits(7), | |
1 == bits(8), | |
8 == bits(255), | |
1 == bits(256)]. | |
testAll() -> | |
[testArea(), testPerimeter(), testEnclose(), testBits()]. | |
allTestsPass() -> | |
lists:min(lists:flatten(testAll())). |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment