module Music.Theory.Math where
import Data.Maybe
import Data.Ratio
import Numeric
import qualified Music.Theory.Math.Convert as T
type R = Double
integral_and_fractional_parts :: (Integral i, RealFrac t) => t -> (i,t)
integral_and_fractional_parts n =
if n >= 0
then let n' = floor n in (n',n fromIntegral n')
else let n' = ceiling n in (n',n fromIntegral n')
integer_and_fractional_parts :: RealFrac t => t -> (Integer,t)
integer_and_fractional_parts = integral_and_fractional_parts
fractional_part :: RealFrac a => a -> a
fractional_part = snd . integer_and_fractional_parts
real_floor :: (Real r,Integral i) => r -> i
real_floor = floor . T.real_to_double
real_floor_int :: Real r => r -> Int
real_floor_int = real_floor
real_round :: (Real r,Integral i) => r -> i
real_round = round . T.real_to_double
real_round_int :: Real r => r -> Int
real_round_int = real_round
zero_to_precision :: Real r => Int -> r -> Bool
zero_to_precision k r = real_floor_int (r * (fromIntegral ((10::Int) ^ k))) == 0
whole_to_precision :: Real r => Int -> r -> Bool
whole_to_precision k = zero_to_precision k . fractional_part . T.real_to_double
sawtooth_wave :: RealFrac a => a -> a
sawtooth_wave n = n floor_f n
rational_pp :: (Show a,Integral a) => Ratio a -> String
rational_pp r =
let n = numerator r
d = denominator r
in if d == 1
then show n
else concat [show n,"/",show d]
ratio_pp :: Rational -> String
ratio_pp r =
let (n,d) = rational_nd r
in concat [show n,":",show d]
rational_simplifies :: Integral a => (a,a) -> Bool
rational_simplifies (n,d) = gcd n d /= 1
rational_nd :: Ratio t -> (t,t)
rational_nd r = (numerator r,denominator r)
rational_whole :: Integral a => Ratio a -> Maybe a
rational_whole r = if denominator r == 1 then Just (numerator r) else Nothing
rational_whole_err :: Integral a => Ratio a -> a
rational_whole_err = fromMaybe (error "rational_whole") . rational_whole
show_rational_decimal :: Int -> Rational -> String
show_rational_decimal n r =
let d = round (abs r * 10^n)
s = show (d :: Integer)
s' = replicate (n length s + 1) '0' ++ s
(h, f) = splitAt (length s' n) s'
in (if r < 0 then "-" else "") ++ h ++ "." ++ f
realfloat_pp :: RealFloat a => Int -> a -> String
realfloat_pp k n = showFFloat (Just k) n ""
real_pp :: Real t => Int -> t -> String
real_pp k t = showFFloat (Just k) (T.real_to_double t) ""
float_pp :: Int -> Float -> String
float_pp = realfloat_pp
double_pp :: Int -> Double -> String
double_pp = realfloat_pp
num_diff_str :: (Num a, Ord a, Show a) => a -> String
num_diff_str n =
case compare n 0 of
LT -> '-' : show (abs n)
EQ -> ""
GT -> '+' : show n
floor_f :: (RealFrac a, Num b) => a -> b
floor_f = fromInteger . floor
round_to :: RealFrac n => n -> n -> n
round_to a b = if a == 0 then b else floor_f ((b / a) + 0.5) * a
oi_mod :: Integral a => a -> a -> a
oi_mod n m = ((n 1) `mod` m) + 1
oi_divMod :: Integral t => t -> t -> (t, t)
oi_divMod n m = let (i,j) = (n 1) `divMod` m in (i,j + 1)
i_square_root :: Integral t => t -> t
i_square_root n =
let babylon a =
let b = quot (a + quot n a) 2
in if a > b then babylon b else a
in case compare n 0 of
GT -> babylon n
EQ -> 0
_ -> error "i_square_root: negative?"
in_open_interval :: Ord a => (a, a) -> a -> Bool
in_open_interval (p,q) n = p < n && n < q
in_closed_interval :: Ord a => (a, a) -> a -> Bool
in_closed_interval (p,q) n = p <= n && n <= q
in_left_half_open_interval :: Ord a => (a, a) -> a -> Bool
in_left_half_open_interval (p,q) n = p < n && n <= q
in_right_half_open_interval :: Ord a => (a, a) -> a -> Bool
in_right_half_open_interval (p,q) n = p <= n && n < q