-module ( factorial ) . -author ( 'Russel Winder' ) . -export ( [ recursive / 1 , tailRecursive / 1 ] ) . -ifdef ( TEST ) . -include_lib ( "eunit/include/eunit.hrl" ) . -endif . recursive ( 0 ) -> 1 ; recursive ( N ) when N > 0 -> N * recursive ( N - 1 ) ; recursive ( N ) when N < 0 -> erlang:error ( { factorialRecursiveNegativeArgument , N } ) . tailRecursive ( 0 ) -> 1 ; tailRecursive ( N ) when N > 0 -> iterate ( 1 , N , 1 ) ; tailRecursive ( N ) when N < 0 -> erlang:error ( { factorialTailRecursiveNegativeArgument , N } ) . iterate ( N , Max , Result ) when N > Max -> Result ; iterate ( N , Max , Result ) -> iterate ( N + 1 , Max , Result * N ) . -ifdef ( TEST ) . %%%%%%%%%%%%%%%%%%%% % % The unit tests. testData ( ) -> [ { 0 , 1 } , { 1 , 1 } , { 2 , 2 } , { 3 , 6 } , { 4 , 24 } , { 5 , 120 } , { 6 , 720 } , { 7 , 5040 } , { 8 , 40320 } , { 9 , 362880 } , { 10 , 3628800 } , { 11 , 39916800 } , { 12 , 479001600 } , { 13 , 6227020800 } , { 14 , 87178291200 } , { 20 , 2432902008176640000 } , { 30 , 265252859812191058636308480000000 } , { 40 , 815915283247897734345611269596115894272000000000 } ] . recursive_test_ ( ) -> [ ?_assertEqual ( R , recursive ( I ) ) || { I , R } <- testData ( ) ] . tailRecursive_test_ ( ) -> [ ?_assertEqual ( R , tailRecursive ( I ) ) || { I , R } <- testData ( ) ] . negativeValues ( ) -> [ -100 , -20 , -5 , -4 , -3 , -2 , -1 ] . negativeParametersRecursive_test_ ( ) -> [ ?_assertError ( { factorialRecursiveNegativeArgument , N } , recursive ( N ) ) || N <- negativeValues ( ) ] . negativeParametersTailRecursive_test_ ( ) -> [ ?_assertError ( { factorialTailRecursiveNegativeArgument , N } , tailRecursive ( N ) ) || N <- negativeValues ( ) ] . -endif .