On Sun, Jun 29, 2014 at 03:11:06PM -0700, Jacek Królikowski wrote:
> Now my question is - how sound is this idea? Is there a reason why this
> shouldn't be done? I can see that most code could be rewritten not to need
> it but I can imagine situations where having numeric limits in spire would
> be benefitial.
Hi Jacek,
I've thought about adding something like this. So far I am undecided.
One point in its favor is that it would be pretty easy to do. I could
easily imagine something like:
trait Limits[A] {
def minValue: Option[A]
def maxValue: Option[A]
}
The reason I've hesitated is that I can't think of a situation where
you would want to use the min/max values without knowing more about
the type. For example, if you look at Double.MaxValue, the "next"
highest value is ~1e292 smaller. I can't think of a generic algorithm
where that would be useful.
Furthermore, we'd have to decide what laws we expected Limits[A]
instances to follow. For example, we might wan to say something like:
forAll { (a: A) =>
Limits[A].maxValue should be >= a
}
However, for Double this would not be correct (due to NaN). We could
say that "Limits[A].maxValue should not be < a" instead, but you see
the problem. Also, how does PositiveInfinity fit in? It's certainly
larger than Double.MaxValue.
I'm open to adding this type class, but I'd like to make sure it's
something that could be useful. We might want something more specific,
like:
trait IsFinite[A] {
def minValue: A
def maxValue: A
}
Or possibly something that capture more of the type's structure, e.g.
trait FloatingPoint[@sp(Float, Double) A] {
def positiveInfinity: A
def negativeInfinity: A
def nan: A
def minValue: A
def maxValue: A
def zero: A
def isFinite(a: A): Boolean
def isInfinite(a: A): Boolean
def isNaN(a: A): Boolean
def ulp(a: A): A
// and so on...
}
Anyway, what do you all think? Are there uses for max value and min
value that I'm missing?
-- Erik