Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic Numeric division

As a general rule, we can take any value of any number type, and divide it by any non-zero value of any number type, and get a reasonable result.

212.7 / 6   // Double = 35.449999999999996
77L / 2.1F  // Float = 36.666668

The one exception, that I've found, is that we can't mix a BigInt with a fractional type (Float or Double).

In the realm of generics, however, there's this interesting distinction between Integral and Fractional types.

// can do this
def divideI[I](a: I, b: I)(implicit ev: Integral[I])   = ev.quot(a,b)

// or this
def divideF[F](a: F, b: F)(implicit ev: Fractional[F]) = ev.div(a,b)

// but not this
def divideN[N](a: N, b: N)(implicit ev: Numeric[N])    = ev.???(a,b)

While I am curious as to why this is, the real question is: Is there some kind of workaround available to sidestep this limitation?

like image 409
jwvh Avatar asked Oct 31 '16 21:10

jwvh


2 Answers

The reason is because integer division and float division are two very different operations, so all Numerics do not share a common division operation, although humans might think of them both as "division."

The workaround would be to create 4 division operations: Integral/Integral, Integral/Fractional, Fractional/Integral, Fractional/Fractional. Do the calculation in whatever application-specific way you feel is appropriate. When I did this for a calculator I wrote, I kept it in Integral if possible, and cast to Double otherwise.

like image 169
Karl Bielefeldt Avatar answered Nov 01 '22 22:11

Karl Bielefeldt


My understanding is that these traits describe sets closed under defined operations:

Numeric is closed under plus, minus, times, negate,

Fractional adds div (i.e. plus, minus, times, negate, div),

Integral adds quot and rem (i.e. plus, minus, times, negate, quot, rem).

Why do you want to sidestep it?

like image 29
Victor Moroz Avatar answered Nov 01 '22 21:11

Victor Moroz