logfloat 0.8.4 → 0.8.5
raw patch · 4 files changed
+105/−466 lines, 4 filessetup-changedPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- Data/Number/LogFloat.hs +102/−92
- Data/Number/LogFloat.lhs +0/−332
- Setup.hs +1/−40
- logfloat.cabal +2/−2
Data/Number/LogFloat.hs view
@@ -1,14 +1,10 @@--- %% This module should be run through lhs2hs before running through--- %% Haddock. (N.B. rember to include a copy in the cabalized)--- %%--- %% This module was originally translated from my Perl module--- %% Math::LogFloat (version 0.3; revision 2007.12.20)--- %% --- %% N.B. Can't have `#' in the first column in GHC, not even if lhs--- -- TODO: Add QuickCheck-ness, though beware of the fuzz. -- TODO: Make sure rewrite rules really fire--- TODO: profile to make sure we don't waste too much time constructing dictionaries+-- TODO: profile to make sure we don't waste too much time constructing+-- dictionaries+-- TODO: investigate adding strictness annotations for register+-- unboxing+-- TODO: write the signed variant -- -- To turn on optimizations and look at the optimization records, cf: -- http://www.haskell.org/ghc/docs/latest/html/users_guide/rewrite-rules.html@@ -20,6 +16,7 @@ {-# OPTIONS_GHC -O2 -fvia-C -optc-O3 #-} -- Version History+-- (v0.8.5) Gave up and converted from lhs to hs so Hackage docs work -- (v0.8.4) Broke out Transfinite -- (v0.8.3) Documentation updates -- (v0.8.2) Announced release@@ -33,7 +30,7 @@ -- (v0.1) Initial version created for hw5 for NLP with Jason Eisner. -- ------------------------------------------------------------------- ~ 2008.08.16+-- ~ 2008.08.16 -- | -- Module : Data.Number.LogFloat -- Copyright : Copyright (c) 2007--2008 wren ng thornton@@ -43,29 +40,25 @@ -- Portability : portable -- -- This module presents a type for storing numbers in the log-domain.--- The main reason for doing this is to prevent underflow when multiplying--- many small probabilities as is done in Hidden Markov Models and--- other statistical models often used for natural language processing.--- The log-domain also helps prevent overflow when multiplying many--- large numbers. In rare cases it can speed up numerical computation--- (since addition is faster than multiplication, though logarithms--- are exceptionally slow), but the primary goal is to improve accuracy--- of results. A secondary goal has been to maximize efficiency since--- these computations are frequently done within a /O(n^3)/ loop.+-- The main reason for doing this is to prevent underflow when+-- multiplying many small probabilities as is done in Hidden Markov+-- Models and other statistical models often used for natural+-- language processing. The log-domain also helps prevent overflow+-- when multiplying many large numbers. In rare cases it can speed+-- up numerical computation (since addition is faster than+-- multiplication, though logarithms are exceptionally slow), but+-- the primary goal is to improve accuracy of results. A secondary+-- goal has been to maximize efficiency since these computations+-- are frequently done within a /O(n^3)/ loop. ----- The 'LogFloat' of this module is restricted to non-negative numbers--- for efficiency's sake, see the forthcoming "Data.Number.LogFloat.Signed"--- for doing signed log-domain calculations.+-- The 'LogFloat' of this module is restricted to non-negative+-- numbers for efficiency's sake, see the forthcoming+-- "Data.Number.LogFloat.Signed" for doing signed log-domain+-- calculations. ---------------------------------------------------------------- module Data.Number.LogFloat (- -- * Documentation Note- -- | If you see no module description above, then the @lhs2hs@- -- script was not run correctly. Please rebuild the documentation- -- or see:- -- <http://code.haskell.org/~wren/logfloat/dist/doc/html/logfloat/>- -- * Basic functions log, toFractional @@ -85,12 +78,12 @@ ---------------------------------------------------------------- ----- Try to add in some optimizations. Why the first few need to be down--- here and localized to the module, I don't know. We don't do anything--- foolish like this, but our clients might, or they might be generated--- by other code transformations. Note that due to the fuzz, these--- equations are not actually true, even though they are mathematically--- correct.+-- Try to add in some optimizations. Why the first few need to be+-- down here and localized to the module, I don't know. We don't+-- do anything foolish like this, but our clients might, or they+-- might be generated by other code transformations. Note that due+-- to the fuzz, these equations are not actually true, even though+-- they are mathematically correct. {-# RULES "log/exp" forall x. log (exp x) = x@@ -100,9 +93,9 @@ "exp.log" exp . log = id #-} --- These are general rule versions of our operators for 'LogFloat'. I--- had some issues inducing 'Ord' on @x@ and @y@, even though they're--- 'Num' so I can't do "(+)\/log" and "(-)\/log" so easily.+-- These are general rule versions of our operators for 'LogFloat'.+-- I had some issues inducing 'Ord' on @x@ and @y@, even though+-- they're 'Num' so I can't do "(+)\/log" and "(-)\/log" so easily. {-# RULES "(*)/log" forall x y. log x * log y = log (x + y)@@ -112,30 +105,40 @@ ---------------------------------------------------------------- ----- | Since the normal 'Prelude.log' throws an error on zero, we have--- to redefine it in order for things to work right. Arguing from--- limits we can see that @log 0 == negativeInfinity@.+-- | Since the normal 'Prelude.log' throws an error on zero, we+-- have to redefine it in order for things to work right. Arguing+-- from limits we can see that @log 0 == negativeInfinity@. Newer+-- versions of GHC have this behavior already, but older versions+-- and Hugs do not. ----- In order to improve portability, the 'Transfinite' class is required--- to indicate that the 'Floating' type does in fact have a representation--- for negative infinity. Both native @Floating@ types ('Double' and--- 'Float') are supported. If you define your own instance of--- @Transfinite@, verify the above equation holds for your @0@ and--- @negativeInfinity@. If it doesn't, then you should avoid importing--- our @log@ and will probably want converters to handle the discrepancy--- when dealing with @LogFloat@s.+-- This function will raise an error when taking the log of negative+-- numbers, rather than returning 'notANumber' as the newer GHC+-- implementation does. The reason being that typically this is a+-- logical error, and @notANumber@ allows the error to propegate+-- silently.+--+-- In order to improve portability, the 'Transfinite' class is+-- required to indicate that the 'Floating' type does in fact have+-- a representation for negative infinity. Both native floating+-- types ('Double' and 'Float') are supported. If you define your+-- own instance of @Transfinite@, verify the above equation holds+-- for your @0@ and @negativeInfinity@. If it doesn't, then you+-- should avoid importing our @log@ and will probably want converters+-- to handle the discrepancy when dealing with @LogFloat@s. {-# SPECIALIZE log :: Double -> Double #-} log :: (Floating a, Transfinite a) => a -> a-log 0 = negativeInfinity-log x = Prelude.log x+log x = case compare x 0 of+ GT -> Prelude.log x+ EQ -> negativeInfinity+ LT -> errorOutOfRange "log" -- | The most generic numeric converter I can come up with. All the--- built-in numeric types are 'Real', though 'Int' and 'Integer' aren't--- 'Fractional'. Beware that converting transfinite values into @Ratio@--- types is error-prone and non-portable, as discussed in--- "Data.Number.Transfinite".+-- built-in numeric types are 'Real', though 'Int' and 'Integer'+-- aren't 'Fractional'. Beware that converting transfinite values+-- into @Ratio@ types is error-prone and non-portable, as discussed+-- in "Data.Number.Transfinite". {-# SPECIALIZE toFractional :: (Real a) => a -> Double #-} {-# SPECIALIZE toFractional :: (Fractional b) => Double -> b #-}@@ -169,11 +172,13 @@ guardNonNegative fun x | x >= 0 = x | otherwise = errorOutOfRange fun --- | It's unfortunate that notANumber is not equal to itself, but we--- can hack around that. Is there any efficiency difference between--- these two tests? If not, then we could use @log . guardNonNegative--- fun = guardIsANumber fun . log@ in order to remove guardNonNegative. +-- | It's unfortunate that notANumber is not equal to itself, but+-- we can hack around that. GHC gives NaN for the log of negatives+-- and so we could ideally take advantage of @log . guardNonNegative+-- fun = guardIsANumber fun . log@ to simplify things, but Hugs+-- raises an error so that's non-portable.+ guardIsANumber :: String -> Double -> Double guardIsANumber fun x | Prelude.isNaN x = errorOutOfRange fun | otherwise = x@@ -183,26 +188,27 @@ -- | A @LogFloat@ is just a 'Double' with a special interpretation. -- The 'logFloat' function is presented instead of the constructor, -- in order to ensure semantic conversion. At present the 'Show'--- instance will convert back to the normal-domain, and so will underflow--- at that point. This behavior may change in the future.+-- instance will convert back to the normal-domain, and so will+-- underflow at that point. This behavior may change in the future. ----- Performing operations in the log-domain is cheap, prevents underflow,--- and is otherwise very nice for dealing with miniscule probabilities.--- However, crossing into and out of the log-domain is expensive and--- should be avoided as much as possible. In particular, if you're--- doing a series of multiplications as in @lp * logFloat q * logFloat--- r@ it's faster to do @lp * logFloat (q * r)@ if you're reasonably--- sure the normal-domain multiplication won't underflow, because that--- way you enter the log-domain only once, instead of twice.+-- Performing operations in the log-domain is cheap, prevents+-- underflow, and is otherwise very nice for dealing with miniscule+-- probabilities. However, crossing into and out of the log-domain+-- is expensive and should be avoided as much as possible. In+-- particular, if you're doing a series of multiplications as in+-- @lp * logFloat q * logFloat r@ it's faster to do @lp * logFloat+-- (q * r)@ if you're reasonably sure the normal-domain multiplication+-- won't underflow, because that way you enter the log-domain only+-- once, instead of twice. ----- Even more particularly, you should /avoid addition/ whenever possible.--- Addition is provided because it's necessary at times and the proper--- implementation is not immediately transparent. However, between two--- @LogFloat@s addition requires crossing the exp\/log boundary twice;--- with a @LogFloat@ and a regular number it's three times since the--- regular number needs to enter the log-domain first. This makes addition--- incredibly slow. Again, if you can parenthesize to do plain operations--- first, do it!+-- Even more particularly, you should /avoid addition/ whenever+-- possible. Addition is provided because it's necessary at times+-- and the proper implementation is not immediately transparent.+-- However, between two @LogFloat@s addition requires crossing the+-- exp\/log boundary twice; with a @LogFloat@ and a regular number+-- it's three times since the regular number needs to enter the+-- log-domain first. This makes addition incredibly slow. Again,+-- if you can parenthesize to do plain operations first, do it! newtype LogFloat = LogFloat Double deriving (Eq, Ord)@@ -220,17 +226,19 @@ -- constructor. We present it mainly because we hide the constructor -- in order to make the type a bit more opaque. If the polymorphism -- turns out to be a performance liability because the rewrite rules--- can't remove it, then we need to rethink all four constructors\/destructors.+-- can't remove it, then we need to rethink all four+-- constructors\/destructors. ----- | Constructor which assumes the argument is already in the log-domain.+-- | Constructor which assumes the argument is already in the+-- log-domain. {-# SPECIALIZE logToLogFloat :: Double -> LogFloat #-} logToLogFloat :: (Real a) => a -> LogFloat logToLogFloat = LogFloat . guardIsANumber "logToLogFloat" . toFractional --- | Return our log-domain value back into normal-domain. Beware of--- overflow\/underflow.+-- | Return our log-domain value back into normal-domain. Beware+-- of overflow\/underflow. {-# SPECIALIZE fromLogFloat :: LogFloat -> Double #-} fromLogFloat :: (Fractional a, Transfinite a) => LogFloat -> a@@ -245,8 +253,8 @@ -- These are our module-specific versions of "log\/exp" and "exp\/log";--- They do the same things but also have a @LogFloat@ in between the--- logarithm and exponentiation.+-- They do the same things but also have a @LogFloat@ in between+-- the logarithm and exponentiation. {-# RULES -- Out of log-domain and back in@@ -262,13 +270,14 @@ #-} ------------------------------------------------------------------- To show it, we want to show the normal-domain value rather than the--- log-domain value. Also, if someone managed to break our invariants--- (e.g. by passing in a negative and noone's pulled on the thunk yet)--- then we want to crash before printing the constructor, rather than--- after. N.B. This means the show will underflow\/overflow in the--- same places as normal doubles since we underflow at the exp. Perhaps--- this means we should show the log-domain value instead.+-- To show it, we want to show the normal-domain value rather than+-- the log-domain value. Also, if someone managed to break our+-- invariants (e.g. by passing in a negative and noone's pulled on+-- the thunk yet) then we want to crash before printing the+-- constructor, rather than after. N.B. This means the show will+-- underflow\/overflow in the same places as normal doubles since+-- we underflow at the @exp@. Perhaps this means we should show the+-- log-domain value instead. instance Show LogFloat where show (LogFloat x) = let y = exp x@@ -280,8 +289,9 @@ -- they tend to induce more of the floating-point fuzz than using -- regular floating numbers because @exp . log@ doesn't really equal -- @id@. In any case, our main aim is for preventing underflow when--- multiplying many small numbers (and preventing overflow for multiplying--- many large numbers) so we're not too worried about +\/- 4e-16.+-- multiplying many small numbers (and preventing overflow for+-- multiplying many large numbers) so we're not too worried about+-- +\/- 4e-16. instance Num LogFloat where (*) (LogFloat x) (LogFloat y) = LogFloat (x+y)@@ -329,4 +339,4 @@ toRational (LogFloat x) = toRational (exp x) ------------------------------------------------------------------- ----------------------------------------------------------- fin.+----------------------------------------------------------- fin.
− Data/Number/LogFloat.lhs
@@ -1,332 +0,0 @@-%% This module should be run through lhs2hs before running through-%% Haddock. (N.B. rember to include a copy in the cabalized)-%%-%% This module was originally translated from my Perl module-%% Math::LogFloat (version 0.3; revision 2007.12.20)-%% -%% N.B. Can't have `#' in the first column in GHC, not even if lhs--TODO: Add QuickCheck-ness, though beware of the fuzz.-TODO: Make sure rewrite rules really fire-TODO: profile to make sure we don't waste too much time constructing dictionaries--To turn on optimizations and look at the optimization records, cf:-http://www.haskell.org/ghc/docs/latest/html/users_guide/rewrite-rules.html-http://www.randomhacks.net/articles/2007/02/10/map-fusion-and-haskell-performance--> -- {-# OPTIONS_GHC -ddump-simpl-stats #-}->-> {-# OPTIONS_GHC -Wall -Werror #-}-> {-# OPTIONS_GHC -O2 -fvia-C -optc-O3 #-}--Version History-(v0.8.4) Broke out Transfinite-(v0.8.3) Documentation updates-(v0.8.2) Announced release-(v0.8) Did a bunch of tweaking. Things should be decent now-(v0.7) Haddockified-(v0.6) Fixed monomorphism.-(v0.5) Added optimization rules.-(v0.4) Translated to Haskell at revision 2007.12.20.-(v0.3) Converted extensive comments to POD format.-(v0.2) Did a bunch of profiling, optimizing, and debugging.-(v0.1) Initial version created for hw5 for NLP with Jason Eisner.------------------------------------------------------------------- ~ 2008.08.16-|-Module : Data.Number.LogFloat-Copyright : Copyright (c) 2007--2008 wren ng thornton-License : BSD3-Maintainer : wren@community.haskell.org-Stability : stable-Portability : portable--This module presents a type for storing numbers in the log-domain.-The main reason for doing this is to prevent underflow when multiplying-many small probabilities as is done in Hidden Markov Models and-other statistical models often used for natural language processing.-The log-domain also helps prevent overflow when multiplying many-large numbers. In rare cases it can speed up numerical computation-(since addition is faster than multiplication, though logarithms-are exceptionally slow), but the primary goal is to improve accuracy-of results. A secondary goal has been to maximize efficiency since-these computations are frequently done within a /O(n^3)/ loop.--The 'LogFloat' of this module is restricted to non-negative numbers-for efficiency's sake, see the forthcoming "Data.Number.LogFloat.Signed"-for doing signed log-domain calculations.-------------------------------------------------------------------> module Data.Number.LogFloat-> (-> -- * Documentation Note-> -- | If you see no module description above, then the @lhs2hs@-> -- script was not run correctly. Please rebuild the documentation-> -- or see:-> -- <http://code.haskell.org/~wren/logfloat/dist/doc/html/logfloat/>->-> -- * Basic functions-> log, toFractional->-> -- * @LogFloat@ data type and conversion functions-> , LogFloat-> , logFloat, logToLogFloat-> , fromLogFloat, logFromLogFloat->-> -- * Exceptional numeric values-> , module Data.Number.Transfinite-> ) where-> -> import Prelude hiding (log, isNaN)-> import qualified Prelude (log, isNaN)->-> import Data.Number.Transfinite--------------------------------------------------------------------Try to add in some optimizations. Why the first few need to be down-here and localized to the module, I don't know. We don't do anything-foolish like this, but our clients might, or they might be generated-by other code transformations. Note that due to the fuzz, these-equations are not actually true, even though they are mathematically-correct.--> {-# RULES-> "log/exp" forall x. log (exp x) = x-> "log.exp" log . exp = id->-> "exp/log" forall x. exp (log x) = x-> "exp.log" exp . log = id-> #-}--These are general rule versions of our operators for 'LogFloat'. I-had some issues inducing 'Ord' on @x@ and @y@, even though they're-'Num' so I can't do "(+)\/log" and "(-)\/log" so easily.--> {-# RULES-> "(*)/log" forall x y. log x * log y = log (x + y)-> "(/)/log" forall x y. log x / log y = log (x - y)-> #-}---------------------------------------------------------------------| Since the normal 'Prelude.log' throws an error on zero, we have-to redefine it in order for things to work right. Arguing from-limits we can see that @log 0 == negativeInfinity@.--In order to improve portability, the 'Transfinite' class is required-to indicate that the 'Floating' type does in fact have a representation-for negative infinity. Both native @Floating@ types ('Double' and-'Float') are supported. If you define your own instance of-@Transfinite@, verify the above equation holds for your @0@ and-@negativeInfinity@. If it doesn't, then you should avoid importing-our @log@ and will probably want converters to handle the discrepancy-when dealing with @LogFloat@s.--> {-# SPECIALIZE log :: Double -> Double #-}-> log :: (Floating a, Transfinite a) => a -> a-> log 0 = negativeInfinity-> log x = Prelude.log x---| The most generic numeric converter I can come up with. All the-built-in numeric types are 'Real', though 'Int' and 'Integer' aren't-'Fractional'. Beware that converting transfinite values into @Ratio@-types is error-prone and non-portable, as discussed in-"Data.Number.Transfinite".--> {-# SPECIALIZE toFractional :: (Real a) => a -> Double #-}-> {-# SPECIALIZE toFractional :: (Fractional b) => Double -> b #-}-> toFractional :: (Real a, Fractional b) => a -> b-> toFractional = fromRational . toRational->-> -- This should only fire when it's type-safe-> {-# RULES "toFractional/id" toFractional = id #-}->-> -- This should happen already, but who knows-> -- TODO: see if it ever fires-> {-# RULES-> "toFractional/toFractional" forall x.-> toFractional (toFractional x) = toFractional x-> "toFractional.toFractional" toFractional . toFractional = toFractional-> #-}---------------------------------------------------------------------| Reduce the number of constant string literals we need to store.--> errorOutOfRange :: String -> a-> errorOutOfRange fun = error $ "Data.Number.LogFloat."++fun-> ++ ": argument out of range"---| We need these guards in order to ensure some invariants.--> guardNonNegative :: String -> Double -> Double-> guardNonNegative fun x | x >= 0 = x-> | otherwise = errorOutOfRange fun--| It's unfortunate that notANumber is not equal to itself, but we-can hack around that. Is there any efficiency difference between-these two tests? If not, then we could use @log . guardNonNegative-fun = guardIsANumber fun . log@ in order to remove guardNonNegative.--> guardIsANumber :: String -> Double -> Double-> guardIsANumber fun x | Prelude.isNaN x = errorOutOfRange fun-> | otherwise = x--------------------------------------------------------------------| A @LogFloat@ is just a 'Double' with a special interpretation.-The 'logFloat' function is presented instead of the constructor,-in order to ensure semantic conversion. At present the 'Show'-instance will convert back to the normal-domain, and so will underflow-at that point. This behavior may change in the future.--Performing operations in the log-domain is cheap, prevents underflow,-and is otherwise very nice for dealing with miniscule probabilities.-However, crossing into and out of the log-domain is expensive and-should be avoided as much as possible. In particular, if you're-doing a series of multiplications as in @lp * logFloat q * logFloat-r@ it's faster to do @lp * logFloat (q * r)@ if you're reasonably-sure the normal-domain multiplication won't underflow, because that-way you enter the log-domain only once, instead of twice.--Even more particularly, you should /avoid addition/ whenever possible.-Addition is provided because it's necessary at times and the proper-implementation is not immediately transparent. However, between two-@LogFloat@s addition requires crossing the exp\/log boundary twice;-with a @LogFloat@ and a regular number it's three times since the-regular number needs to enter the log-domain first. This makes addition-incredibly slow. Again, if you can parenthesize to do plain operations-first, do it!--> newtype LogFloat = LogFloat Double-> deriving (Eq, Ord)---| A constructor which does semantic conversion from normal-domain-to log-domain.--> {-# SPECIALIZE logFloat :: Double -> LogFloat #-}-> logFloat :: (Real a) => a -> LogFloat-> logFloat = LogFloat . log . guardNonNegative "logFloat" . toFractional---This is simply a polymorphic version of the 'LogFloat' data-constructor. We present it mainly because we hide the constructor-in order to make the type a bit more opaque. If the polymorphism-turns out to be a performance liability because the rewrite rules-can't remove it, then we need to rethink all four constructors\/destructors.--| Constructor which assumes the argument is already in the log-domain.--> {-# SPECIALIZE logToLogFloat :: Double -> LogFloat #-}-> logToLogFloat :: (Real a) => a -> LogFloat-> logToLogFloat = LogFloat . guardIsANumber "logToLogFloat" . toFractional---| Return our log-domain value back into normal-domain. Beware of-overflow\/underflow.--> {-# SPECIALIZE fromLogFloat :: LogFloat -> Double #-}-> fromLogFloat :: (Fractional a, Transfinite a) => LogFloat -> a-> fromLogFloat (LogFloat x) = toFractional (exp x)---| Return the log-domain value itself without costly conversion--> {-# SPECIALIZE logFromLogFloat :: LogFloat -> Double #-}-> logFromLogFloat :: (Fractional a, Transfinite a) => LogFloat -> a-> logFromLogFloat (LogFloat x) = toFractional x---These are our module-specific versions of "log\/exp" and "exp\/log";-They do the same things but also have a @LogFloat@ in between the-logarithm and exponentiation.--> {-# RULES-> -- Out of log-domain and back in-> "log/fromLogFloat" forall x. log (fromLogFloat x) = logFromLogFloat x-> "log.fromLogFloat" log . fromLogFloat = logFromLogFloat->-> "logFloat/fromLogFloat" forall x. logFloat (fromLogFloat x) = x-> "logFloat.fromLogFloat" logFloat . fromLogFloat = id->-> -- Into log-domain and back out-> "fromLogFloat/logFloat" forall x. fromLogFloat (logFloat x) = x-> "fromLogFloat.logFloat" fromLogFloat . logFloat = id-> #-}-------------------------------------------------------------------To show it, we want to show the normal-domain value rather than the-log-domain value. Also, if someone managed to break our invariants-(e.g. by passing in a negative and noone's pulled on the thunk yet)-then we want to crash before printing the constructor, rather than-after. N.B. This means the show will underflow\/overflow in the-same places as normal doubles since we underflow at the exp. Perhaps-this means we should show the log-domain value instead.--> instance Show LogFloat where-> show (LogFloat x) = let y = exp x-> in y `seq` "LogFloat "++show y--------------------------------------------------------------------These all work without causing underflow. However, do note that-they tend to induce more of the floating-point fuzz than using-regular floating numbers because @exp . log@ doesn't really equal-@id@. In any case, our main aim is for preventing underflow when-multiplying many small numbers (and preventing overflow for multiplying-many large numbers) so we're not too worried about +\/- 4e-16.--> instance Num LogFloat where -> (*) (LogFloat x) (LogFloat y) = LogFloat (x+y)->-> (+) (LogFloat x) (LogFloat y)-> | x >= y = LogFloat (x + log (1 + exp (y - x)))-> | otherwise = LogFloat (y + log (1 + exp (x - y)))->-> -- Without the guard this would return NaN instead of error-> (-) (LogFloat x) (LogFloat y)-> | x >= y = LogFloat (x + log (1 - exp (y - x)))-> | otherwise = errorOutOfRange "(-)"->-> signum (LogFloat x)-> | x == negativeInfinity = 0-> | x > negativeInfinity = 1-> | otherwise = errorOutOfRange "signum"-> -- The extra guard protects against NaN, in case someone-> -- broke the invariant. That shouldn't be possible and-> -- so noone else bothers to check, but we check here just-> -- in case.->-> negate _ = errorOutOfRange "negate"->-> abs = id->-> fromInteger = LogFloat . log-> . guardNonNegative "fromInteger" . fromInteger->->-> instance Fractional LogFloat where-> -- n/0 is handled seamlessly for us; we must catch 0/0 though-> (/) (LogFloat x) (LogFloat y)-> | x == negativeInfinity-> && y == negativeInfinity = errorOutOfRange "(/)" -- protect vs NaN-> | otherwise = LogFloat (x-y)-> -> fromRational = LogFloat . log-> . guardNonNegative "fromRational" . fromRational->->-> -- Just for fun. The more coersion functions the better. Though-> -- it can underflow...-> instance Real LogFloat where-> toRational (LogFloat x) = toRational (exp x)------------------------------------------------------------------------------------------------------------------------------ fin.
Setup.hs view
@@ -1,46 +1,7 @@ #!/usr/bin/env runhaskell module Main (main) where---- <http://www.haskell.org/ghc/docs/latest/html/libraries/Cabal/Distribution-Simple.html> import Distribution.Simple-import Distribution.Simple.Setup (CleanFlags, HaddockFlags)-import Distribution.Simple.LocalBuildInfo (LocalBuildInfo)-import Distribution.PackageDescription (HookedBuildInfo- , emptyHookedBuildInfo- , PackageDescription- )-import System.Cmd (system) main :: IO ()-main = defaultMainWithHooks simpleUserHooks- { preHaddock = preHaddockScript- , postClean = postCleanScript- }---preHaddockScript :: Args -> HaddockFlags -> IO HookedBuildInfo-preHaddockScript _ _ = do - putStrLn "Building lhs2hs..."- system "ghc --make lhs2hs.hs -o lhs2hs"- putStrLn "Illiterating Data.Number.LogFloat for Haddock..."- system "./lhs2hs Data/Number/LogFloat.lhs Data/Number/LogFloat.hs"- return emptyHookedBuildInfo---postCleanScript :: Args- -> CleanFlags- -> PackageDescription- -> Maybe LocalBuildInfo- -> IO ()-postCleanScript _ _ _ _ = do - putStrLn $ "removing files: " ++ commafy files- removeAll files- where- files = ["Data/Number/LogFloat.hs", "lhs2hs", "lhs2hs.hi", "lhs2hs.o"]- - removeAll = sequence_ . map (system . (++) "rm -f ")- - commafy [] = ""- commafy [x] = x- commafy (x:xs@(_:_)) = x++", "++commafy xs+main = defaultMain
logfloat.cabal view
@@ -1,8 +1,8 @@ ---------------------------------------------------------------- Name: logfloat-Version: 0.8.4+Version: 0.8.5 Cabal-Version: >= 1.2-Build-Type: Custom+Build-Type: Simple Stability: stable Copyright: Copyright (c) 2007--2008 wren ng thornton License: BSD3