How can I multiply a INumber with an int?

How can I multiply a INumber with an int?


15

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
3


21

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

Fiddle

1

  • I wander if there could have been an interface that supports the implicit converters int to TResult.

    – Wouter

    19 hours ago


12

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 only IMultiplyOperators<decimal,decimal,decimal>

    – Wouter

    yesterday


  • @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 to TResult using Convert.ChangeType, but I kind of feel that defeats the point of generic maths slightly, so I'm not sure.

    – ProgrammingLlama

    yesterday


  • indeed 2 was just an example (could have added z + z). Maybe there is an interface to do the (implicit) conversion?

    – Wouter

    yesterday


  • Injection of Func<TResult, int, TResult> multiply to this function will work.

    – Wouter

    yesterday


4

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 Karonen

    yesterday




Leave a Reply

Your email address will not be published. Required fields are marked *