module Zora.Math
(
primes
, composites
, prime
, coprime
, euler_phi
, factor
, divisors
, irrational_squares
, sqrt_convergents
, continued_fraction_sqrt
, continued_fraction_sqrt_infinite
, is_int
, is_power_of_int
, int_to_double
, num_digits
, tri_area
, tri_area_double
) where
import qualified Data.List as List
import Data.Maybe
import Zora.List
primes :: [Integer]
primes = [2, 3, 5] ++ (diff_infinite [7, 9 ..] composites)
composites :: [Integer]
composites = foldr1 f $ map g $ tail primes
where
f (x:xt) ys = x : (merge_infinite xt ys)
g p = [ n * p | n <- [p, p + 2 ..]]
merge_infinite :: (Ord a) => [a] -> [a] -> [a]
merge_infinite xs@(x:xt) ys@(y:yt) =
case compare x y of
LT -> x : (merge_infinite xt ys)
EQ -> x : (merge_infinite xt yt)
GT -> y : (merge_infinite xs yt)
prime_rec :: Integer -> Integer -> Bool
prime_rec n k
| (n <= 1) = False
| (fromInteger k >= ((fromInteger n) / 2) + 1.0) = True
| ((n `mod` k) == 0) = False
| otherwise = prime_rec n (k+1)
prime :: Integer -> Bool
prime n = prime_rec n 2
coprime :: Integer -> Integer -> Bool
coprime a b = isNothing . List.find is_common_divisor $ [2..(min a' b')]
where
a' :: Integer
a' = abs a
b' :: Integer
b' = abs b
is_common_divisor :: Integer -> Bool
is_common_divisor n = (a `mod` n == 0) && (b `mod` n == 0)
euler_phi_for_powers_of_primes :: (Integer, Integer) -> Integer
euler_phi_for_powers_of_primes (p, a) = p^(a1) * (p1)
euler_phi :: Integer -> Integer
euler_phi 1 = 0
euler_phi n = product
$ map
euler_phi_for_powers_of_primes
$ map format $ List.group $ factor n
where
format l = (head l, (toInteger . length) l)
factor :: Integer -> [Integer]
factor 0 = []
factor 1 = []
factor n = p : factor (n `div` p)
where p = fromJust . List.find (\p -> (n `mod` p) == 0) $ primes
divisors :: Integer -> [Integer]
divisors = init . uniqueify . map product . powerset . factor
sqrt_convergents_rec :: (Integer, Integer) -> (Integer, Integer) -> [Integer] -> [(Integer, Integer)]
sqrt_convergents_rec (a'', b'') (a', b') cf =
(a, b) : sqrt_convergents_rec (a', b') (a, b) cf'
where
a = e * a' + a''
b = e * b' + b''
e = head cf
cf' = tail cf
sqrt_convergents :: Integer -> [(Integer, Integer)]
sqrt_convergents n =
(a0, b0) : (a1, b1) :
sqrt_convergents_rec
(a0, b0)
(a1, b1)
(tail . tail $ cf)
where
(a0, b0) = (e, 1)
(a1, b1) = (e * e' + 1, e')
e = head cf
e' = head . tail $ cf
cf = continued_fraction_sqrt_infinite n
irrational_squares :: [Integer]
irrational_squares = map round $ filter (not . is_int . sqrt) [1..]
next_continued_fraction_sqrt :: (Integer, Integer, Integer, Integer, Integer) -> (Integer, Integer, Integer, Integer, Integer)
next_continued_fraction_sqrt (d, m, a, a0, n) = (d', m', a', a0, n)
where
d' = (n m'^2) `div` d
m' = (d * a) m
a' = floor $ (fromIntegral (a0 + m')) / (fromIntegral d')
continued_fraction_sqrt_infinite :: Integer -> [Integer]
continued_fraction_sqrt_infinite n =
map trd5
$ iterate next_continued_fraction_sqrt (d0, m0, a0, a0, n)
where
m0 = 0
d0 = 1
a0 = floor . sqrt . fromInteger $ n
trd5 (_, _, x, _, _) = x
continued_fraction_sqrt :: Integer -> [Integer]
continued_fraction_sqrt n =
take_while_keep_last (/= (2 * a0)) . continued_fraction_sqrt_infinite $ n
where
a0 = floor . sqrt . fromInteger $ n
tri_area :: Integer -> Integer -> Integer -> Double
tri_area a b c =
sqrt $ p * (pa') * (pb') * (pc')
where
a' = fromInteger a
b' = fromInteger b
c' = fromInteger c
p = (fromInteger (a + b + c)) / 2
tri_area_double :: Double -> Double -> Double -> Double
tri_area_double a b c =
sqrt $ p * (pa) * (pb) * (pc)
where
p = (a + b + c) / 2
is_power_of_int :: Integer -> Integer -> Bool
is_power_of_int n e = (round (fromIntegral n ** (1/(fromInteger e))))^e == n
num_digits :: Integer -> Integer
num_digits n = (1 + (floor $ logBase 10 (fromInteger n)))
is_int :: Double -> Bool
is_int x = x == (fromInteger (round x))
int_to_double :: Double -> Integer
int_to_double = (toInteger . round)