6

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?

jwvh
  • 50,871
  • 7
  • 38
  • 64

2 Answers2

7

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.

Karl Bielefeldt
  • 47,314
  • 10
  • 60
  • 94
  • Yes, that would work IFF you know the number types, so they can't be `Numeric`. In fact, you can't use `Integral` or `Fractional` because the compiler won't allow you to overload the method (i.e. it can't discriminate between method parameters of those types). In order to have a method that "does the math" for any number type, it looks like I'd have to forgo generics and overload the method for all reasonable combinations of number types (primitives). – jwvh Nov 04 '16 at 06:16
4

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?

Victor Moroz
  • 9,167
  • 1
  • 19
  • 23
  • I'd like to be able to perform the same (more or less) simple math operations as can be done with the primitive types without restricting the user (calling code) to `Integral` or `Fractional`. I want to give the user the widest input options (any `Numeric`) while hiding the implementation (the math operations to get the result). Easy to do if the math ops are limited to `+`, `-`, and `*`. It seems odd that `/` is not included in that set. – jwvh Oct 31 '16 at 23:46