diff --git a/subprojects/bahaghari/lib/default.nix b/subprojects/bahaghari/lib/default.nix index be45de9f..627e1a40 100644 --- a/subprojects/bahaghari/lib/default.nix +++ b/subprojects/bahaghari/lib/default.nix @@ -48,5 +48,5 @@ pkgs.lib.makeExtensible isNumber scale; inherit (self.hex) isHexString; - inherit (self.math) abs pow percentage; + inherit (self.math) abs pow percentage factorial round round' summate product; }) diff --git a/subprojects/bahaghari/lib/math.nix b/subprojects/bahaghari/lib/math.nix index d5f82fba..a34683a3 100644 --- a/subprojects/bahaghari/lib/math.nix +++ b/subprojects/bahaghari/lib/math.nix @@ -4,6 +4,9 @@ { pkgs, lib, self }: rec { + pi = 3.141592653589793238462643383279502884197; + e = 2.7182818284590452353602874713527; + /* Returns the absolute value of the given number. Type: abs :: Int -> Int @@ -41,6 +44,22 @@ rec { in if exponent < 0 then (1 / value) else value; + /* Implements the factorial function with the given value. + + Type: factorial :: Number -> Number + + Example: + factorial 3 + => 6 + + factorial 10 + => 3628800 + */ + factorial = x: + assert lib.assertMsg (x >= 0) + "bahaghariLib.math.factorial: given value is not a positive integer"; + product (lib.range 1 x); + /* Returns a boolean whether the given number is within the given (inclusive) range. Type: isWithinRange :: Number -> Number -> Number -> Bool @@ -110,7 +129,7 @@ rec { then 0 else number / (100.0 / value); - /* Given a number, round up (or down) its number to the nearest integer. + /* Given a number, round up (or down) its number to the nearest ones place. Type: round :: Number -> Number @@ -125,9 +144,54 @@ rec { => 3 */ round = number: + round' 0 number; + + /* Given a tens place (10 ^ n) and a number, round the nearest integer to its + given place. + + Type: round' :: Number -> Number -> Number + + Example: + # Round the number to the nearest ones. + round' 0 5.65 + => 6 + + # Round the number to the nearest tens. + round' 1 5.65 + => 10 + + # Round the number to the nearest hundreds. + round' 2 5.65 + => 0 + + # Round the number to the nearest tenth. + round' (-1) 5.65 + => 5.7 + */ + round' = tens: number: let - number' = builtins.floor number; - difference = number - number'; + nearest = pow 10.0 tens; + difference = number / nearest; in - if difference >= 0.5 then (number' + 1) else number'; + builtins.floor (difference + 0.5) * nearest; + + /* Adds all of the given items on the list starting from a sum of zero. + + Type: summate :: List[Number] -> Number + + Example: + summate [ 1 2 3 4 ] + => 10 + */ + summate = builtins.foldl' builtins.add 0; + + /* Multiply all of the given items on the list starting from a product of 1. + + Type: product :: List[Number] -> Number + + Example: + product [ 1 2 3 4 ] + => 24 + */ + product = builtins.foldl' builtins.mul 1; } diff --git a/subprojects/bahaghari/tests/lib/math.nix b/subprojects/bahaghari/tests/lib/math.nix index f25ab4fd..08356434 100644 --- a/subprojects/bahaghari/tests/lib/math.nix +++ b/subprojects/bahaghari/tests/lib/math.nix @@ -16,6 +16,11 @@ lib.runTests { expected = 1; }; + testsMathPowWithFloat = { + expr = self.math.pow 2 7.0; + expected = 128.0; + }; + testMathAbsoluteValue = { expr = self.math.abs 5493; expected = 5493; @@ -86,6 +91,31 @@ lib.runTests { expected = 3; }; + testMathRoundOnes = { + expr = self.math.round' 0 5.65; + expected = 6; + }; + + testMathRoundTens = { + expr = self.math.round' 1 5.65; + expected = 10; + }; + + testMathRoundHundreds = { + expr = self.math.round' 2 5.65; + expected = 0; + }; + + testMathRoundTenth = { + expr = self.math.round' (-1) 5.65; + expected = 5.7; + }; + + testMathRoundHundredth = { + expr = self.math.round' (-2) 5.655; + expected = 5.66; + }; + testMathWithinRange = { expr = self.math.isWithinRange (-100) 100 50; expected = true; @@ -95,4 +125,39 @@ lib.runTests { expr = self.math.isWithinRange 5 10 (-5); expected = false; }; + + testMathFactorial = { + expr = self.math.factorial 3; + expected = 6; + }; + + testMathFactorial2 = { + expr = self.math.factorial 10; + expected = 3628800; + }; + + testMathFactorialZero = { + expr = self.math.factorial 0; + expected = 1; + }; + + testMathSummate = { + expr = self.math.summate [ 1 2 3 4 ]; + expected = 10; + }; + + testMathSummate22 = { + expr = self.math.summate [ 1 2 3 4.5 5.6 6.7 ]; + expected = 22.8; + }; + + testMathProduct = { + expr = self.math.product [ 1 2 3 4 ]; + expected = 24; + }; + + testMathProduct2 = { + expr = self.math.product [ 1.5 2 3 4.6 ]; + expected = 41.4; + }; }