A Floating Point Filter [1] provides a Numeric
type that wraps another
Numeric
type, but defers its computation, instead providing a floating
point (Double
) approximation.
A typeclass approach to wrapping numeric types in an FPFilter
.
A typeclass approach to wrapping numeric types in an FPFilter
. This way
was chosen, as not all conversions are lossy, so we want to be able to
capture those lossless conversions (Int
, Float
, Double
, some BigInt
s
and Long
s, etc.), while still handling the generic case that is lossy.
A MaybeDouble
will hold a Double
approximation so long as the Double
's
sign can be computed exactly.
A MaybeDouble
will hold a Double
approximation so long as the Double
's
sign can be computed exactly. It is not a general number type, but is meant
to be used in tandem with a more accurate, but slow (computationally),
number type. When performing comparisons then, this can be checked first to
save on potentially slow computation.
For this type, if a method returns an Option
al value, then that indicates
that if None
is returned, the answer cannot be computed exactly, but if
Some(x)
is returned, then that is guaranteed to be correct. For example,
toLong
, toFloat
, sign
, isWhole
, etc. return these types of optional,
only-if-correct, type values.
Most likely you would not use this directly, but just wrap your number type
in a FPFilter
which maintains a MaybeDouble
and handles all the lazy
computation of the more accurate number type for you.
TODO: genericFPFilter is constantly being chosen over the ones defined here.
TODO: genericFPFilter is constantly being chosen over the ones defined here. Does prioritized implicit selection work differently here for some odd reason? What the heck...
A Long
encoded version of MaybeDouble
, geared for unboxed speed.
A Long
encoded version of MaybeDouble
, geared for unboxed speed. This
is significantly less accurate, but may provide good speed gains in common
cases.
The values approx
and measure
are both truncated floats with the full
8 bit exponent, but only 16 bit mantissa. Since the measure
is always
positive, we only need 2 * (16 + 8) + 1 = 49
bits for these 2 numbers,
which leaves 15 bits for the index
. These sizes were chosen so that
worst case relative error, ind * eps
, has a value less than 1. In our
case, with worst case ind = -1 >>> 17
, we have ind * eps =~ 0.5
.
This was inspired by Erik Osheim's awesome FastComplex, which encodes the
imaginary and real parts as 2 Float
s in the a single Long
.
TODO: Perhaps, if we've only used + or *, we could store a higher precision float instead, since we don't need measure. Use 1 bit to handle the switching, taken from the index.
A Floating Point Filter [1] provides a
Numeric
type that wraps anotherNumeric
type, but defers its computation, instead providing a floating point (Double
) approximation. For some operations, likesignum
, comparisons, equality checks, toFloat, etc, theDouble
approximation may be used to compute the result, rather than having to compute the exact value.An
FPFilter
can generally be used with anyRing
numeric type (also supportsEuclideanRing
,Field
, andExponential
). However, it should be kept in mind thatFPFilter
knows nothing about the type its wrapping and assumes that, generally, it is more accurate than it is. When anFPFilter
cannot determine an answer to some predicate exactly, it will defer to the wrapped value, so it probably doesn't make sense to wrapInt
s, when anInt
will overflow before aDouble
!Good candidates to wrap in
FPFilter
areBigInt
s,Rational
s, andBigDecimal
s. Note thatAlgebraic
uses anFPFilter
internally and thus nothing is gained by wrapping it. The reasoning behind this is thatFPFilter
s add quite a bit of space requirements, as they may hold onto the entire expression tree (as call-by-name paramters), and, sinceAlgebraic
also does this by design, the asymptotic space requirements remain the same.Currently, the only way to operate on an
FPFilter
is by using its various numeric typeclasses.Note: Don't use
FPFilter
s in hash maps. Getting thehashCode
will always force the evaluation ofvalue
.[1] Burnikel, Funke, Seel. Exact Geometric Computation Using Cascading. SoCG 1998.