# rounded-hw: Rounding control for built-in floating-point types

This package provides directed rounding and interval arithmetic for built-in floating-point types (i.e. `Float`, `Double`).
Unlike [rounded](https://hackage.haskell.org/package/rounded), this package does not depend on an external C library.

In addition to `Float` and `Double`, `LongDouble` from [long-double](https://hackage.haskell.org/package/long-double) package is supported on x86.
There is also support for `Float128` from [float128](https://hackage.haskell.org/package/float128) package under a package flag.

# API overview

## Controlling the rounding direction

The type `RoundingMode` represents the four rounding directions.

The type `Rounded (r :: RoundingMode) a` is a wrapper for `a`, with instances honoring the rounding direction given by `r`.

```haskell
module Numeric.Rounded.Hardware where

data RoundingMode
  = ToNearest     -- ^ Round to the nearest value (IEEE754 roundTiesToEven)
  | TowardNegInf  -- ^ Round downward (IEEE754 roundTowardNegative)
  | TowardInf     -- ^ Round upward (IEEE754 roundTowardPositive)
  | TowardZero    -- ^ Round toward zero (IEEE754 roundTowardZero)

newtype Rounded (r :: RoundingMode) a = Rounded { getRounded :: a }

instance ... => Num (Rounded r a)
instance ... => Fractional (Rounded r a)
instance ... => Real (Rounded r a)
instance ... => RealFrac (Rounded r a)
```

## Interval arithmetic

This library also provides basic interval types. See `Numeric.Rounded.Hardware.Interval` and `Numeric.Rounded.Hardware.Interval.NonEmpty`.

# Usage

```haskell
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE HexFloatLiterals #-}
import Numeric
import Numeric.Rounded.Hardware

main = do
  putStrLn $ showHFloat (1 + 0x1p-100 :: Double) "" -- -> 0x1p0
  putStrLn $ showHFloat (1 + 0x1p-100 :: Rounded TowardInf Double) "" -- -> 0x1.0000000000001p0
```

# Backends

There are several options to control the rounding direction.

* Pure Haskell (via `Rational`)
    * Very slow, but does not depend on FFI and therefore can be used on non-native backends.
    * This implementation is always available via a newtype in `Numeric.Rounded.Hardware.Backend.ViaRational`.
* C FFI
    * One of the technologies below is used:
        * C99 (`fesetround`)
        * SSE2 (`_mm_setcsr`)
        * AVX512 EVEX encoding (`_mm_*_round_*`)
        * x87 Control Word (for x87 long double)
        * AArch64 FPCR
    * On x86_64, `foreign import prim` is used to provide faster interval addition/subtraction.

By default, C FFI is used and an appropriate technology is detected.
To disable use of C FFI, set `pure-hs` flag when building.

The name of the backend used can be obtained with `Numeric.Rounded.Hardware.Backend.backendName`.

```haskell
>>> backendName (Proxy :: Proxy Double)
"FastFFI+SSE2"
```
