Consider the following methods:
static T Divide<T>(T dividend, T divisor) where T : INumber<T>
{
return dividend / divisor;
}
static T DivideF<T>(T dividend, T divisor) where T : IFloatingPoint<T>
{
return T.Floor(dividend / divisor);
}
The reason I have two of them is that I want the division to behave the same way regardless of whether the value is an integer or floating point, hence the reason that DivideF
calls T.Floor
(which is a member of IFloatingPoint<T>
and not a member of INumber<T>
).
The methods cannot have the same name, because the method signature does not account for the generic constraint, but I would like, if possible to be able to combine these methods into a single method; something like this:
static T Divide<T>(T dividend, T divisor) where T : INumber<T>
{
if (typeof(T) == typeof(IFloatingPoint<>))
{
return T.Floor(dividend / divisor);
}
return dividend / divisor;
}
This code doesn't work, firstly because typeof(T) == typeof(IFloatingPoint<>)
is false even when T
is inferred from a value that implements IFloatingPoint<T>
, and T.Floor
isn't available within the if
block anyway.
Is it possible to combine the methods into a single method?
One not very elegant solution is to implement Floor
(in this case, probably very naively).
private static T Floor<T>(T value) where T : INumber<T>
{
T result = T.Zero;
while (value > T.Zero)
{
if (value < T.One)
{
return result;
}
value -= T.One;
result++;
}
return result;
}
static T Divide<T>(T dividend, T divisor) where T : INumber<T>
{
return Floor(dividend / divisor);
}
In fact, I could even just implement Divide
by hand, so that I don't need Floor
...
static T Divide<T>(T dividend, T divisor) where T : INumber<T>
{
if (divisor == T.Zero)
{
throw new DivideByZeroException("Divisor cannot be zero.");
}
if (divisor == T.One)
{
return dividend;
}
if (divisor == -T.One)
{
return -dividend;
}
T dividendSign = T.IsNegative(dividend) ? -T.One : T.One;
T divisorSign = T.IsNegative(divisor) ? -T.One : T.One;
T sign = dividendSign * divisorSign;
dividend = T.Abs(dividend);
divisor = T.Abs(divisor);
dividend -= dividend % divisor;
return dividend / divisor * sign;
}