如何将 INumber<T> 与 int 相乘?[复制]

How can I multiply a INumber<T> with an int? [duplicate]

提问人:Wouter 提问时间:10/16/2023 最后编辑:Guru StronWouter 更新时间:10/31/2023 访问量:1937

问:

我应该如何在最后一行实现 int() 乘法?z * 2

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;
}

---建议的解决方案是添加一个接口,但它破坏了这一点: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
}

现在,我将自己注入函数并使用:

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;
}
C# 数学 数字 net-7.0 . net-generic-math

评论


答:

16赞 ProgrammingLlama 10/16/2023 #1

您需要添加接口:IMultiplyOperators<, ,>

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;
}

您可以在此处查看操作员界面列表。

评论

0赞 Wouter 10/16/2023
Althoug 这确实有效。看看十进制.cs,它不仅实现了接口IMultiplyOperators<TResult, int, TResult>IMultiplyOperators<decimal,decimal,decimal>
0赞 ProgrammingLlama 10/16/2023
@Wouter恐怕我实际上并不知道在这种情况下十进制的解决方案。一个适用于乘以 2 的简单解决方案只是增加自身,但这绝对不会扩展。另一种方法可能是将整数 2 转换为使用 ,但我有点觉得这稍微违背了通用数学的意义,所以我不确定。zTResultConvert.ChangeType
0赞 Wouter 10/16/2023
事实上,2 只是一个例子(可以添加 Z + Z)。也许有一个接口可以进行(隐式)转换?
0赞 Wouter 10/16/2023
注入到此函数将起作用。Func<TResult, int, TResult> multiply
25赞 Dmitry Bychenko 10/16/2023 #2

我建议转换为然后再乘:2TResult

   TResult z2 = z * TResult.CreateChecked(2);

在这里,我们从整数值创建实例,同时检查溢出和类似的可能错误(如果无法转换为:either 或 ),将抛出异常。TResult222TResultOverflowExceptionNotSupportedException

法典:

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;
}

演示:

Console.WriteLine(Test<decimal>());

输出:

0

小提琴

评论

0赞 Wouter 10/17/2023
我徘徊着是否可以有一个支持隐式转换器 int 到 TResult 的接口。
1赞 Damien_The_Unbeliever 10/18/2023
@Wouter - 隐式转换应始终是安全的。你怎么对你的信念/断言如此有信心,这些信念/断言总是可以转换为任何将执行数学的领域,以便应该存在式转换而不是显式转换?2
0赞 Wouter 10/18/2023
我的意思是,就像添加一个接口一样,如果十进制实现它,转换就不需要“CreateCheck”,它只是一个大开关,并不是真正的多态/类型安全。IImplicitConvert<int, TResult>
6赞 Olivier Jacot-Descombes 10/17/2023 #3

虽然不是通用解决方案,但在这种情况下(乘数 = 2),您可以简单地写成:

TResult z2 = z + z;

除了 z 是 TResult.AdditiveIdentity * TResult.MultiplicativeIdentity。但 TResult.AdditiveIdentity 为零。所以结果将为零。

评论

6赞 Ilmari Karonen 10/17/2023
更一般地说,任何整数的乘法都可以在数学上定义(如果需要,也可以实现)重复加法(可能是否定)。在实践中,您需要实现类似农民乘法算法的东西,该算法可以仅使用 O(log n) 加法(以及一些整数位操作)将数字乘以整数 n。当然,这样做的结果可能与“原生”整数乘法的行为相匹配,也可能不匹配,尽管对于相当理智的数字类型来说,它确实应该。
0赞 Wouter 10/18/2023
这是一个最小的例子,它表明乘法正在 TResult 上工作。接下来,将其乘以浮点数/双倍数怎么样。甚至是另一个 INumber?public static void Test<X, Y>(X x, Y y) where X : INumber<X> where Y : INumber<Y> => Console.WriteLine(x * y);