Math functions in Haskell explained with literate programming
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

9.1 KiB

title author license
Math Functions Josias Allestad CC0-1.0

Some math functions I wrote for fun.

All possible copyright (and neighboring rights) is waived from this document with the CC0-1.0 legal tool.

Misc

These are general functions are are useful elsewhere but are simple and don't really fit in any of the other categories.

The reciprocal of a number is the same as that number to the power of -1.

reciprocal x = x^^(-1)

Halve a sorted list, remove the middle if required. Input should be sorted in most situations.

halve :: [a] -> ([a], [a])
halve xs =
    if even (length xs)
        then (take halfLen xs, drop halfLen xs)
        else (take halfLen xs, drop (halfLen+1) xs)
  where
    halfLen = (length xs) `div` 2

Fun Algorithms

These are just some fun algorithms that have little practical purpose for me now.

The collatz conjecture states that if you take any number $n$, and if even divide by two and if odd multiply by three and add one ($3n+1$), and keep doing so, it will eventually get to 1.

collatz :: Int -> Int
collatz = docollatz 0
  where
    docollatz x (-1) = x
    docollatz y x
      | x == 1 = y
      | odd x = docollatz (x * 3 + 1) (y + 1)
      | even x = docollatz (x `div` 2) (y + 1)
      | otherwise = 1

Quadratic

These are functions related to the quadratic equation.

$$ax^2+bx+c$$

<<quadratic-equation>>
<<quadratic-check>>

Solve the quadratic formula for x in an equation.

$$\frac{-b+\sqrt{b^2-4ac}}{2a}$$

(I can't seem to put "+ or -" properly into the formula above)

qEquation :: (Float, Float, Float) -> (Float, Float)
qEquation (a, b, c) = (x1, x2)
  where
    x1 = e + sqrt d / (2 * a)
    x2 = e - sqrt d / (2 * a)
    d = b * b - 4 * a * c
    e = - b / (2 * a)

Verify that a solution checks in the quadratic equation.

qCheck :: (Num a, Eq a) => (a, a, a) -> a -> Bool
qCheck (a, b, c) x = a*x^2 + b*x + c == 0

Linear

These are functions relating to linear equations and functions.

Slope-intercept form of a linear equation:

$$y=mx+b$$

<<linear-solve>>
<<linear-distance>>
<<linear-slope>>
<<linear-midpoint>>
<<linear-perpendicular-bisector>>

Solve $y=mx+b$ when provided with x:

solveLinear m b x = m*x + b

The distance between two points on a graph can be calculated with the equation:

$$\sqrt{(x2 - x1)^2 + (y2 - y1)^2}$$

distance :: Floating a => ((a, a), (a, a)) -> a
distance ((x1, y1), (x2, y2)) = sqrt ((x2 - x1)^2 + (y2 - y1)^2)

The slope of a line between two points:

$$m=\frac{x2-x1}{y2-y1}$$

slope ((x1, y1), (x2, y2)) = (y2 - y1) / (x2 - x1)

The midpoint of a graph can be be represented as $(x, y)$, where $x=(x1+x2)/2$ and $y=(y1+y2)/2$.

midpoint ((x1, y1), (x2, y2)) = (x, y)
  where
    x = (x1 + x2) / 2
    y = (y1 + y2) / 2

The perpendicular bisector of a point on a graph is a line which cuts a line segment into two equal parts at 90 degrees.

These steps find the equation for the perpendicular bisector of a point:

  1. Find the midpoint, and the slope of the two points
  2. Find the negative reciprocal of the slope
  3. Put the negative reciprocal of the slope as the slope in $y=mx+b$
  4. Put the x and y of the midpoint into $y=mx+b$
  5. Solve for b
  6. Write in form $y=mx+b$ substituting $m$ for the negative reciprocal of the original slope, and $b$ for the solution of the last step.
perpBisec ((x1, y1), (x2, y2)) = (a, b)
  where
    a = - reciprocal (slope ((x1, y1), (x2, y2)))
    b = perpBisecIntercept ((x1, y1), (x2, y2))

Get the intercept of a perpendicular bisector:

perpBisecIntercept ((x1, y1), (x2, y2)) = midy - r*midx
  where
    (midx, midy) = midpoint ((x1, y1), (x2, y2))
    m = slope ((x1, y1), (x2, y2))
    r = - reciprocal m

Pythagorean

The Pythagorean theorem states that for any right triangle, the squares of the length of the legs equals the square of the length of the hypotenuse.

$$a^2+b^2=c^2$$

The length of a leg of a right triangle can be found with $\sqrt{c^2 - a^2}$.

pyFindAB a c = sqrt (c^2 - a^2)

The length of the hypotenuse of a right triange can be found with $\sqrt{a^2+b^2}$.

pyFindC a b = sqrt (a^2 + b^2)

The Pythagorean theorem can be expanded to apply to the diagonal distance between two points in a rectangular prism.

$$ d^2=x^2+y^2+z^2 $$

To find $d$, simply find the square root of $ x^2+y^2+z^2 $.

prismFindD x y z = sqrt (x^2 + y^2 + z^2)

Finding x, y, or z is very similar to finding the legs in a right triangle, but the direct extended equation ($ b=\sqrt{a^2-a^2} $) ends up with the right answer multiplied by $ \sqrt{-1} $ (bi). To avoid that, this equation can be used: $ z=\sqrt{-1 * (x^2+y^2-d^2)} $.

prismFindXYZ x y d = sqrt (-(x^2 + y^2 - d^2))

A triangle can be shown to be a right triangle or not by seeing if $a^2+b^2=c^2$.

isRight a b c = a^2 + b^2 == c^2

When $x$ is in a Pythagorean equation as $ (ax)^2 + (bx)^2 = c^2 $, $x$ can be found with the following equation:

$$ \sqrt{c^2 / (a^2 + b^2)} $$

pySolveX a b c = sqrt (c^2 / (a^2 + b^2))

Now we need to be able to check that an x-value fits into the original equation:

pyCheckX a b c x = (a*x)^2 + (b*x)^2 == c^2

Variation

Direct variation equation: $$ y=ax $$

Inverse variation equation: $$ y=\frac{a}{x} $$

In both cases $a$ may not be 0.

Graphs of direct variation equations are linear, while the graphs of the inverse variation equation is a hyperbola.

Mean, Standard Deviation, etc

Get the mean of a list. $$ \bar{x}=\frac{x_1+x_2+...+x_n}{n} $$

mean xs = realToFrac (sum xs) / genericLength xs

The median of a numerical data set is the middle number if the number of items in the set is odd, or the mean of the two middle numbers if the length is even.

median :: (Fractional a, Ord a) => [a] -> Maybe a
median xs | odd len = Just (sorted !! mid)
          | even len = Just ((sorted !! (mid - 1) + sorted !! mid) / 2)
          | null xs = Nothing
            where
              mid = len `div` 2
              len = genericLength xs
              sorted = sort xs

We may find use of a function that does the same but doesn't ever return a Maybe.

medianNoMaybe [] = 0
medianNoMaybe xs = fromJust $ median xs

The following describe the spread of data.

meanAbsoluteDeviation xs = sum (map (\x -> abs $ x - mean xs) xs) / fromIntegral (length xs)

variance xs = sum (map (\x -> (x - mean xs)^2) xs) / fromIntegral (length xs)

standardDeviation = sqrt . variance

The upper and lower quartiles are respectively the medians of the upper and lower halves of a set. Those are the second and third quartiles. The second quartile is the median.

Here we use medianNoMaybe because quartiles already covers cases where median returns Nothing (and thus where medianNoMaybe returns 0).

If the list is blank, we can't find any information about it.

quartiles [] = Nothing

If the list has one element, the quartiles are all the same.

quartiles [a] = Just (a, a, a)

Otherwise it's straightforward. The list is divided in half (with the median removed if odd) and the median of each half is calculated.

quartiles xs = Just (medianNoMaybe right, medianNoMaybe xs, medianNoMaybe left)
    where
      (right, left) = halve $ sort xs

An outlier is a value which is widely-separated from the rest of the set. Generally an outlier is considered to be a value greater or less than the upper or lower quartile by more than the interquartile times 1.5.

isOutlier x xs = if upperFence > x || lowerFence < x then True else False
  where
    iqRange = upperQ - lowerQ
    (upperQ, _, lowerQ) = fromJust $ quartiles xs
    lowerFence = lowerQ - iqRange * 1.5
    upperFence = upperQ + iqRange * 1.5

outliers xs = filter (\x -> isOutlier x xs) xs

For these Data.List and Data.Maybe need to be imported.

import Data.Maybe
import Data.List

Complete File

Here is the structure of the file. Not that it really matters here besides the fact that we need to put it all in one file at the end.

<<imports>>
<<misc>>
<<fun>>
<<quadratic>>
<<linear>>
<<pythagorean>>
<<mean>>

Other functions

Well, I guess I lied. This whole thing isn't in Haskell. Here are some other random functions that I find useful.

This bruteforces $x$ in an algebra equation. It's usage of eval is pretty bad, but at least the program works.

def x(left: str, right: str, maximum: int = 1000) -> int:
    for x in range(maximum):
        if eval(left) == eval(right):
            return x