module Numeric.Decimal.Exception ( -- * Exceptional conditions clamped , conversionSyntax , divisionByZero , divisionImpossible , divisionUndefined , inexact , insufficientStorage , invalidContext , invalidOperation , overflow , rounded , subnormal , underflow ) where import Prelude hiding (exponent) import Numeric.Decimal.Arithmetic import Numeric.Decimal.Number import Numeric.Decimal.Precision import Numeric.Decimal.Rounding -- | This occurs and signals 'Clamped' if the exponent of a result has been -- altered in order to fit the constraints of a specific concrete -- representation. This may occur when the exponent of a zero result would be -- outside the bounds of a representation, or (in the IEEE 754 interchange -- formats) when a large normal number would have an encoded exponent that -- cannot be represented. In this latter case, the exponent is reduced to fit -- and the corresponding number of zero digits are appended to the coefficient -- (“fold-down”). The condition always occurs when a subnormal value rounds to -- zero. clamped :: Decimal p r -> Arith p r (Decimal p r) clamped = raiseSignal Clamped -- | This occurs and signals 'InvalidOperation' if a string is being converted -- to a number and it does not conform to the numeric string syntax. The -- result is @[0,qNaN]@. conversionSyntax :: Arith p r (Decimal p r) conversionSyntax = raiseSignal InvalidOperation qNaN -- | This occurs and signals 'DivisionByZero' if division of a finite number -- by zero was attempted (during a 'Numeric.Decimal.Operation.divideInteger' -- or 'Numeric.Decimal.Operation.divide' operation, or a -- 'Numeric.Decimal.Operation.power' operation with negative right-hand -- operand), and the dividend was not zero. -- -- The result of the operation is @[@/sign/@,inf]@, where /sign/ is the -- exclusive or of the signs of the operands for divide, or is 1 for an odd -- power of −0, for power. divisionByZero :: Decimal p r -> Arith p r (Decimal p r) divisionByZero = raiseSignal DivisionByZero -- | This occurs and signals 'InvalidOperation' if the integer result of a -- 'Numeric.Decimal.Operation.divideInteger' or -- 'Numeric.Decimal.Operation.remainder' operation had too many digits (would -- be longer than /precision/). The result is @[0,qNaN]@. divisionImpossible :: Arith p r (Decimal p r) divisionImpossible = raiseSignal InvalidOperation qNaN -- | This occurs and signals 'InvalidOperation' if division by zero was -- attempted (during a 'Numeric.Decimal.Operation.divideInteger', -- 'Numeric.Decimal.Operation.divide', or -- 'Numeric.Decimal.Operation.remainder' operation), and the dividend is also -- zero. The result is @[0,qNaN]@. divisionUndefined :: Arith p r (Decimal p r) divisionUndefined = raiseSignal InvalidOperation qNaN -- | This occurs and signals 'Inexact' whenever the result of an operation is -- not exact (that is, it needed to be rounded and any discarded digits were -- non-zero), or if an overflow or underflow condition occurs. The result in -- all cases is unchanged. -- -- The 'Inexact' signal may be tested (or trapped) to determine if a given -- operation (or sequence of operations) was inexact. inexact :: Decimal p r -> Arith p r (Decimal p r) inexact = raiseSignal Inexact -- | For many implementations, storage is needed for calculations and -- intermediate results, and on occasion an arithmetic operation may fail due -- to lack of storage. This is considered an operating environment error, -- which can be either be handled as appropriate for the environment, or -- treated as an Invalid operation condition. The result is @[0,qNaN]@. insufficientStorage :: Arith p r (Decimal p r) insufficientStorage = invalidOperation qNaN -- | This occurs and signals 'InvalidOperation' if an invalid context was -- detected during an operation. This can occur if contexts are not checked on -- creation and either the /precision/ exceeds the capability of the -- underlying concrete representation or an unknown or unsupported /rounding/ -- was specified. These aspects of the context need only be checked when the -- values are required to be used. The result is @[0,qNaN]@. invalidContext :: Arith p r (Decimal p r) invalidContext = raiseSignal InvalidOperation qNaN -- | This occurs and signals 'InvalidOperation' if: -- -- * an operand to an operation is @[s,sNaN]@ or @[s,sNaN,d]@ (any /signaling/ -- NaN) -- -- * an attempt is made to add @[0,inf]@ to @[1,inf]@ during an addition or -- subtraction operation -- -- * an attempt is made to multiply 0 by @[0,inf]@ or @[1,inf]@ -- -- * an attempt is made to divide either @[0,inf]@ or @[1,inf]@ by either -- @[0,inf]@ or @[1,inf]@ -- -- * the divisor for a remainder operation is zero -- -- * the dividend for a remainder operation is either @[0,inf]@ or @[1,inf]@ -- -- * either operand of the 'Numeric.Decimal.Operation.quantize' operation is -- infinite, or the result of a 'Numeric.Decimal.Operation.quantize' operation -- would require greater precision than is available -- -- * the operand of the 'Numeric.Decimal.Operation.ln' or the -- 'Numeric.Decimal.Operation.log10' operation is less than zero -- -- * the operand of the 'Numeric.Decimal.Operation.squareRoot' operation has a -- /sign/ of 1 and a non-zero /coefficient/ -- -- * both operands of the 'Numeric.Decimal.Operation.power' operation are -- zero, or if the left-hand operand is less than zero and the right-hand -- operand does not have an integral value or is infinite -- -- * an operand is invalid; for example, certain values of concrete -- representations may not correspond to numbers — an implementation is -- permitted (but is not required) to detect these invalid values and raise -- this condition. -- -- The result of the operation after any of these invalid operations is -- @[0,qNaN]@ except when the cause is a signaling NaN, in which case the -- result is @[s,qNaN]@ or @[s,qNaN,d]@ where the sign and diagnostic are -- copied from the signaling NaN. invalidOperation :: Decimal a b -> Arith p r (Decimal p r) invalidOperation n = raiseSignal InvalidOperation $ case n of NaN { signaling = True } -> n { signaling = False } _ -> qNaN -- | This occurs and signals 'Overflow' if the /adjusted exponent/ of a result -- (from a conversion or from an operation that is not an attempt to divide by -- zero), after rounding, would be greater than the largest value that can be -- handled by the implementation (the value E/max/). -- -- The result depends on the rounding mode: -- -- * For 'RoundHalfUp' and 'RoundHalfEven' (and for 'RoundHalfDown' and -- 'RoundUp', if implemented), the result of the operation is [sign,@inf@], -- where /sign/ is the sign of the intermediate result. -- -- * For 'RoundDown', (and 'Round05Up', if implemented), the result is the -- largest finite number that can be represented in the current /precision/, -- with the sign of the intermediate result. -- -- * For 'RoundCeiling', the result is the same as for 'RoundDown' if the sign -- of the intermediate result is 1, or is @[0,inf]@ otherwise. -- -- * For 'RoundFloor', the result is the same as for 'RoundDown' if the sign -- of the intermediate result is 0, or is @[1,inf]@ otherwise. -- -- In all cases, 'inexact' and 'rounded' will also be raised. -- -- Note: IEEE 854 §7.3 requires that the result delivered to a trap handler be -- different, depending on whether the overflow was the result of a conversion -- or of an arithmetic operation. This specification deviates from IEEE 854 in -- this respect; however, an implementation could comply with IEEE 854 by -- providing a separate mechanism for the special result to a trap -- handler. IEEE 754 has no such requirement. overflow :: (Precision p, Rounding r) => Decimal p r -> Arith p r (Decimal p r) overflow ir = result >>= raiseSignal Overflow >>= inexact >>= rounded where result :: (Precision p, Rounding r) => Arith p r (Decimal p r) result = getRounding >>= \r -> case r of RoundHalfUp -> signedInfinity RoundHalfEven -> signedInfinity RoundHalfDown -> signedInfinity RoundUp -> signedInfinity RoundDown -> largestFinite Round05Up -> largestFinite RoundCeiling -> case sign ir of Neg -> largestFinite Pos -> return infinity RoundFloor -> case sign ir of Pos -> largestFinite Neg -> return infinity { sign = Neg } signedInfinity :: Arith p r (Decimal p r) signedInfinity = return infinity { sign = sign ir } largestFinite :: Precision p => Arith p r (Decimal p r) largestFinite = getPrecision >>= \p -> let x = Num { sign = sign ir , coefficient = undefined -- 10^p - 1 , exponent = undefined -- eMax x } in return x -- | This occurs and signals 'Rounded' whenever the result of an operation is -- rounded (that is, some zero or non-zero digits were discarded from the -- coefficient), or if an overflow or underflow condition occurs. The result -- in all cases is unchanged. -- -- The 'Rounded' signal may be tested (or trapped) to determine if a given -- operation (or sequence of operations) caused a loss of precision. rounded :: Decimal p r -> Arith p r (Decimal p r) rounded = raiseSignal Rounded -- | This occurs and signals 'Subnormal' whenever the result of a conversion -- or operation is subnormal (that is, its adjusted exponent is less than -- E/min/, before any rounding). The result in all cases is unchanged. -- -- The 'Subnormal' signal may be tested (or trapped) to determine if a given -- or operation (or sequence of operations) yielded a subnormal result. subnormal :: Decimal p r -> Arith p r (Decimal p r) subnormal = raiseSignal Subnormal -- | This occurs and signals 'Underflow' if a result is inexact and the -- /adjusted exponent/ of the result would be smaller (more negative) than the -- smallest value that can be handled by the implementation (the value -- E/min/). That is, the result is both inexact and subnormal. -- -- The result after an underflow will be a subnormal number rounded, if -- necessary, so that its exponent is not less than E/tiny/. This may result -- in 0 with the sign of the intermediate result and an exponent of E/tiny/. -- -- In all cases, 'inexact', 'rounded', and 'subnormal' will also be raised. -- -- Note: IEEE 854 §7.4 requires that the result delivered to a trap handler be -- different, depending on whether the underflow was the result of a -- conversion or of an arithmetic operation. This specification deviates from -- IEEE 854 in this respect; however, an implementation could comply with IEEE -- 854 by providing a separate mechanism for the result to a trap -- handler. IEEE 754 has no such requirement. underflow :: Decimal p r -> Arith p r (Decimal p r) underflow x = undefined >>= raiseSignal Underflow >>= subnormal >>= inexact >>= rounded