module Zora.Math
(
primes
, nonprimes
, is_prime
, coprime
, euler_phi
, factorize
, divisors
, irr_squares
, sqrt_convergents
, continued_fraction_sqrt
, continued_fraction_sqrt_infinite
, is_int
, is_power_of_int
, int_to_double
, get_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 ..] nonprimes)
nonprimes :: [Integer]
nonprimes = 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)
is_prime_rec :: Integer -> Integer -> Bool
is_prime_rec n k
| (n <= 1) = False
| (fromInteger k >= ((fromInteger n) / 2) + 1.0) = True
| ((n `mod` k) == 0) = False
| otherwise = is_prime_rec n (k+1)
is_prime :: Integer -> Bool
is_prime n = is_prime_rec n 2
coprime :: Integer -> Integer -> Bool
coprime a b = Nothing == List.find is_common_divisor [2..(min a b)]
where
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 $ factorize n
where
format l = (head l, (toInteger . length) l)
factorize :: Integer -> [Integer]
factorize 0 = []
factorize 1 = []
factorize n = p : factorize (n `div` p)
where p = fromJust . List.find (\p -> (n `mod` p) == 0) $ primes
divisors :: Integer -> [Integer]
divisors = init . uniqueify . map product . powerset . factorize
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
irr_squares :: [Integer]
irr_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
get_num_digits :: Integer -> Integer
get_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)