scientific-0.3.3.0: Numbers represented using scientific notation

Maintainer Bas van Dijk None

Data.Scientific

Description

`Data.Scientific` provides a space efficient and arbitrary precision scientific number type.

`Scientific` numbers are represented using scientific notation. It uses an `Integer` `coefficient` `c` and an `Int` `base10Exponent` `e` (do note that since we're using an `Int` to represent the exponent these numbers aren't truly arbitrary precision). A scientific number corresponds to the `Fractional` number: `fromInteger c * 10 ^^ e`.

The main application of `Scientific` is to be used as the target of parsing arbitrary precision numbers coming from an untrusted source. The advantages over using `Rational` for this are that:

• A `Scientific` is more efficient to construct. Rational numbers need to be constructed using `%` which has to compute the `gcd` of the `numerator` and `denominator`.
• `Scientific` is safe against numbers with huge exponents. For example: `1e1000000000 :: Rational` will fill up all space and crash your program. Scientific works as expected:
``` > read "1e1000000000" :: Scientific
1.0e1000000000
```
• Also, the space usage of converting scientific numbers with huge exponents to `Integrals` (like: `Int`) or `RealFloats` (like: `Double` or `Float`) will always be bounded by the target type.

WARNING: Although `Scientific` is an instance of `Fractional`, the methods are only partially defined! Specifically `recip` and `/` will diverge (i.e. loop and consume all space) when their outputs have an infinite decimal expansion. `fromRational` will diverge when the input `Rational` has an infinite decimal expansion.

This module is designed to be imported qualified:

`import Data.Scientific as Scientific`

Synopsis

# Documentation

data Scientific Source

An arbitrary-precision number represented using scientific notation.

This type describes the set of all `Reals` which have a finite decimal expansion.

A scientific number with `coefficient` `c` and `base10Exponent` `e` corresponds to the `Fractional` number: `fromInteger c * 10 ^^ e`

Instances

 Eq Scientific Fractional Scientific WARNING: `recip` and `/` will diverge (i.e. loop and consume all space) when their outputs have an infinite decimal expansion. `fromRational` will diverge when the input `Rational` has an infinite decimal expansion. Data Scientific Num Scientific Ord Scientific Read Scientific Real Scientific WARNING: `toRational` needs to compute the `Integer` magnitude: `10^e`. If applied to a huge exponent this could fill up all space and crash your program! Avoid applying `toRational` (or `realToFrac`) to scientific numbers coming from an untrusted source and use `toRealFloat` instead. The latter guards against excessive space usage. RealFrac Scientific Show Scientific Typeable Scientific NFData Scientific Hashable Scientific

# Construction

`scientific c e` constructs a scientific number which corresponds to the `Fractional` number: `fromInteger c * 10 ^^ e`.

# Projections

The coefficient of a scientific number.

Note that this number is not necessarily normalized, i.e. it could contain trailing zeros.

Scientific numbers are automatically normalized when pretty printed or in `toDecimalDigits`.

Use `normalize` to do manual normalization.

The base-10 exponent of a scientific number.

# Predicates

Return `True` if the scientific is a floating point, `False` otherwise.

Also see: `floatingOrInteger`.

Return `True` if the scientific is an integer, `False` otherwise.

Also see: `floatingOrInteger`.

# Conversions

floatingOrInteger :: (RealFloat r, Integral i) => Scientific -> Either r iSource

`floatingOrInteger` determines if the scientific is floating point or integer. In case it's floating-point the scientific is converted to the desired `RealFloat` using `toRealFloat`.

Also see: `isFloating` or `isInteger`.

toRealFloat :: RealFloat a => Scientific -> aSource

Safely convert a `Scientific` number into a `RealFloat` (like a `Double` or a `Float`).

Note that this function uses `realToFrac` (`fromRational . toRational`) internally but it guards against computing huge Integer magnitudes (`10^e`) that could fill up all space and crash your program. If the `base10Exponent` of the given `Scientific` is too big or too small to be represented in the target type, Infinity or 0 will be returned respectively. Use `toBoundedRealFloat` which explicitly handles this case by returning `Left`.

Always prefer `toRealFloat` over `realToFrac` when converting from scientific numbers coming from an untrusted source.

toBoundedRealFloat :: forall a. RealFloat a => Scientific -> Either a aSource

Preciser version of `toRealFloat`. If the `base10Exponent` of the given `Scientific` is too big or too small to be represented in the target type, Infinity or 0 will be returned as `Left`.

toBoundedInteger :: forall i. (Integral i, Bounded i) => Scientific -> Maybe iSource

Convert a `Scientific` to a bounded integer.

If the given `Scientific` doesn't fit in the target representation, it will return `Nothing`.

This function also guards against computing huge Integer magnitudes (`10^e`) that could fill up all space and crash your program.

fromFloatDigits :: RealFloat a => a -> ScientificSource

Convert a `RealFloat` (like a `Double` or `Float`) into a `Scientific` number.

Note that this function uses `floatToDigits` to compute the digits and exponent of the `RealFloat` number. Be aware that the algorithm used in `floatToDigits` doesn't work as expected for some numbers, e.g. as the `Double` `1e23` is converted to `9.9999999999999991611392e22`, and that value is shown as `9.999999999999999e22` rather than the shorter `1e23`; the algorithm doesn't take the rounding direction for values exactly half-way between two adjacent representable values into account, so if you have a value with a short decimal representation exactly half-way between two adjacent representable values, like `5^23*2^e` for `e` close to 23, the algorithm doesn't know in which direction the short decimal representation would be rounded and computes more digits

# Pretty printing

Arguments

 :: FPFormat -> Maybe Int Number of decimal places to render. -> Scientific -> String

Like `show` but provides rendering options.

data FPFormat

Control the rendering of floating point numbers.

Constructors

 Exponent Scientific notation (e.g. `2.3e123`). Fixed Standard decimal notation. Generic Use decimal notation for values between `0.1` and `9,999,999`, and scientific notation otherwise.

Instances

 Enum FPFormat Read FPFormat Show FPFormat

toDecimalDigits :: Scientific -> ([Int], Int)Source

Similar to `floatToDigits`, `toDecimalDigits` takes a non-negative `Scientific` number, and returns a list of digits and a base-10 exponent. In particular, if `x>=0`, and

``` toDecimalDigits x = ([d1,d2,...,dn], e)
```

then

1. `n >= 1` 2. `x = 0.d1d2...dn * (10^^e)` 3. `0 <= di <= 9` 4. `null \$ takeWhile (==0) \$ reverse [d1,d2,...,dn]`

The last property means that the coefficient will be normalized, i.e. doesn't contain trailing zeros.

# Normalization

Normalize a scientific number by dividing out powers of 10 from the `coefficient` and incrementing the `base10Exponent` each time.

You should rarely have a need for this function since scientific numbers are automatically normalized when pretty-printed and in `toDecimalDigits`.