How should I implement the multiplication by int (z * 2
) on the last line?
public static TResult Test<TResult>() where TResult : INumber<TResult>
{
TResult x = TResult.AdditiveIdentity;
TResult y = TResult.MultiplicativeIdentity;
TResult z = x * y;
TResult z2 = z * 2; // <--- this gives the CS0019 error "The operator * cannot be applied to operands of type 'TResult' and 'int'
return z2;
}
— the suggested solution is to add an interface, but it breaks this:
IMultiplyOperators<TResult, int, TResult>
public static void Tester()
{
Test<decimal>(); // CS0315 Tye type decimal cannot be used as type parameter TResult..... there is no boxing conversion
}
For now I will inject the function myself and use:
public static TResult Test<TResult>(Func<TResult, int, TResult> mul) where TResult : INumber<TResult>
{
TResult x = TResult.AdditiveIdentity;
TResult y = TResult.MultiplicativeIdentity;
TResult z = x * y;
TResult z2 = mul(z, 2);
return z2;
}
3 Answers
I suggest converting 2
to TResult
and only then multiply:
TResult z2 = z * TResult.CreateChecked(2);
Here we create TResult
instance from integer value 2
, while checking 2
for overflow and similar possible errors (an exception will be thrown if 2
can’t be converted into TResult
: either OverflowException
or NotSupportedException
).
Code:
public static TResult Test<TResult>() where TResult : INumber<TResult>
{
TResult x = TResult.AdditiveIdentity;
TResult y = TResult.MultiplicativeIdentity;
TResult z = x * y;
TResult z2 = z * TResult.CreateChecked(2);
return z2;
}
Demo:
Console.WriteLine(Test<decimal>());
Output:
0
1
-
I wander if there could have been an interface that supports the implicit converters int to TResult.
– Wouter19 hours ago
You need to add the IMultiplyOperators<, ,>
interface:
public static TResult Test<TResult>() where TResult : INumber<TResult>, IMultiplyOperators<TResult, int, TResult>
{
TResult x = TResult.AdditiveIdentity;
TResult y = TResult.MultiplicativeIdentity;
TResult z = x * y;
TResult z2 = z * 2;
return z2;
}
You can see the list of operator interfaces here.
4
-
Althoug this does work. Look at decimal.cs it doesn't implement the
IMultiplyOperators<TResult, int, TResult>
interface onlyIMultiplyOperators<decimal,decimal,decimal>
– Wouteryesterday
-
@Wouter I'm afraid I don't actually know the solution for decimal in that case. A simple solution that would work for multiplying by 2 would be just to add
z
to itself, but that definitely wouldn't scale. Another approach might be to convert integer 2 toTResult
usingConvert.ChangeType
, but I kind of feel that defeats the point of generic maths slightly, so I'm not sure.– ProgrammingLlamayesterday
-
indeed 2 was just an example (could have added z + z). Maybe there is an interface to do the (implicit) conversion?
– Wouteryesterday
-
Injection of
Func<TResult, int, TResult> multiply
to this function will work.– Wouteryesterday
While not a general solution, in this very case (multiplier = 2) you can simply write:
TResult z2 = z + z;
Except the z is TResult.AdditiveIdentity * TResult.MultiplicativeIdentity. But TResult.AdditiveIdentity is zero. So the result will be zero.
1
-
5
More generally, multiplication by any integer can be mathematically defined (and, if desired, implemented) in terms of repeated addition (and possibly negation). In practice you'd want to implement something like the peasant multiplication algorithm, which can multiply a number by an integer n using only O(log n) additions (and some integer bit manipulation). Of course the result of this may or may not match the behavior of "native" integer multiplication, although for reasonably sane number types it really should.
– Ilmari Karonenyesterday