implementation module fixed

/*
	Numbers with 5 decimal precision
	
	Pieter Koopman, 2010
	Radboud Universty, Nijmegen
	The Netherlands
	pieter@cs.ru.nl
*/


import StdEnv, BigInt

:: Fixed = Fixed !BigInt

instance toString Fixed
where toString (Fixed bi)
		= (if (bi<zero) "-" "") +++ toString quot +++ toStringFixed PRECISION string (toInt remainder)
		where
			(quot,remainder) = quotRem (abs bi) FACTOR
			string :: *String
			string = {createArray INCPRECISION '0' & [0] = '.'}

toStringFixed :: !Int !*String !Int -> String
toStringFixed n string 0 = string
toStringFixed 0 string remainder = string
toStringFixed n string remainder = toStringFixed (n-1) {string & [n] = '0'+toChar (remainder rem 10)} (remainder/10)

class toFixed a :: a -> Fixed

instance toFixed Int where toFixed i = Fixed (FACTOR * (toBigInt i))
instance toFixed BigInt where toFixed bi = Fixed (FACTOR * bi)
instance toFixed String where toFixed s = stringToFixed zero 0 (size s-1) s

stringToFixed :: !BigInt !Int !Int !String -> Fixed
stringToFixed b i l s
	| i>l // end string
		= toFixed b
	| s.[i] == '.'
		= fracToFixed b 5 (i+1) l s
	| isDigit s.[i]
		= stringToFixed ((b*%10)+%(toInt(s.[i]-'0'))) (i+1) l s
		= toFixed b

fracToFixed b n i l s
	| i>l || n<0
		= Fixed (b*%(10^n))
	| isDigit s.[i]
		= fracToFixed ((b*%10)+%(toInt(s.[i]-'0'))) (n-1) (i+1) l s
		= Fixed (b*%(10^n))

instance ==				Fixed where (==) (Fixed x) (Fixed y) = x == y
instance <				Fixed where (<) (Fixed x) (Fixed y) = x < y

// Arithmetic:

instance +				Fixed where (+) (Fixed x) (Fixed y) = Fixed (x + y)
instance -				Fixed where (-) (Fixed x) (Fixed y) = Fixed (x - y)
instance zero			Fixed where zero = Fixed zero

instance *				Fixed where (*) (Fixed x) (Fixed y) = Fixed ((x * y)/FACTOR)
instance /				Fixed where (/) (Fixed x) (Fixed y) = Fixed ((FACTOR * x) / y)	//	Truncated to 0
instance one 			Fixed where one = Fixed (FACTOR * one)

instance abs 			Fixed where abs (Fixed x) = Fixed (abs x)
instance ~ 				Fixed where ~ (Fixed x) = Fixed (~ x)

instance mod			Fixed where (mod) (Fixed x) (Fixed y) = Fixed (FACTOR * (x mod y))
instance rem			Fixed where (rem) (Fixed x) (Fixed y) = Fixed (FACTOR * (x rem y))

instance toInt			Fixed where toInt (Fixed x) = toInt (x/FACTOR)

FACTOR :: BigInt
FACTOR =: toBigInt (10^PRECISION)

PRECISION :: Int
PRECISION =: 5

INCPRECISION :: Int
INCPRECISION =: PRECISION+1
