module Data.Ratio.Extra where

import Data.Ratio qualified as Ratio

{- | Show a 'Rational' in fixed-point notation, without using scientific notation.

>>> showFixedPoint (1 % 2)
"0.5"
>>> showFixedPoint (-0.1)
"-0.1"
>>> showFixedPoint 10
"10.0"
>>> showFixedPoint 1.154646000
"1.154646"
-}
showFixedPoint :: Rational -> String
showFixedPoint :: Rational -> String
showFixedPoint Rational
rational
  | Integer
numerator Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
< Integer
0 = String
"-" String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
result
  | Bool
otherwise = String
result
 where
  result :: String
result = Integer -> String
forall a. Show a => a -> String
show Integer
whole String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
"." String -> String -> String
forall a. Semigroup a => a -> a -> a
<> [String] -> String
forall (t :: Type -> Type) a. Foldable t => t [a] -> [a]
concat (Integer -> [String]
go0 Integer
fractional)
  (Integer
whole, Integer
fractional) = Integer -> Integer
forall a. Num a => a -> a
abs Integer
numerator Integer -> Integer -> (Integer, Integer)
forall a. Integral a => a -> a -> (a, a)
`quotRem` Integer
denominator
  numerator :: Integer
numerator = Rational -> Integer
forall a. Ratio a -> a
Ratio.numerator Rational
rational
  denominator :: Integer
denominator = Rational -> Integer
forall a. Ratio a -> a
Ratio.denominator Rational
rational

  go0 :: Integer -> [String]
go0 Integer
0 = [String
"0"]
  go0 Integer
i = Integer -> [String]
go1 Integer
i

  go1 :: Integer -> [String]
go1 Integer
0 = []
  go1 Integer
i = Integer -> String
forall a. Show a => a -> String
show Integer
w String -> [String] -> [String]
forall a. a -> [a] -> [a]
: Integer -> [String]
go1 Integer
f
   where
    (Integer
w, Integer
f) = (Integer
10 Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
i) Integer -> Integer -> (Integer, Integer)
forall a. Integral a => a -> a -> (a, a)
`quotRem` Integer
denominator