Search code examples
c#floating-point.net-generic-math

Designing generic types with constraints on generic math interfaces


Consider the following trivial example, which is a struct that represents the square of an ISignedNumber<T>.

public readonly struct Square<T> where T : ISignedNumber<T>
{
    public Square(T value)
    {
        Value = value * value;
    }
    
    public T Value { get; }
}

Square<int> a = new(123);
Console.WriteLine(a.Value); // 15129

Square<long> b = new(1234567);
Console.WriteLine(b.Value); // 1524155677489

Square<BigInteger> c = new(BigInteger.Parse("123456789000000000"));
Console.WriteLine(c.Value); // 15241578750190521000000000000000000

Notably, this implementation will work for anything that implements ISignedNumber<T>, since value * value is possible.

Less trivial is how to build structs that require prior knowledge of known constants; for example, I might want to build a struct that represents the golden ratio of a given number, which requires knowledge of Phi

(phi): φ = (1 + sqrt(5)) / 2 ≈ 1.61803398875

As this value is a constant literal, it cannot be applied where T : IFloatingPoint<T>.

public readonly struct GoldenRatio<T> where T : IFloatingPoint<T>
{
    public static T Phi = 1.61803398875;
}

Cannot convert source type 'double' to target type 'T'

Whilst I assume that the answer is simply that this isn't possible with generic math interfaces, I figured I would ask here anyway, in case there is something that I have overlooked.

The only thing I can think of is that when instances of GoldenRatio<T> are created, the values have to be passed in based on the selected type; i.e. float, double, decimal, but that ultimately restricts the type to only allow a finite set of IFloatingPoint<T> implementations, and at runtime, which isn't very nice.


Solution

  • There are some creation functions you can use to convert from a float number.

    public readonly struct GoldenRatio<T> where T : IFloatingPoint<T>
    {
        public static readonly T Phi = T.CreateChecked(1.61803398875);
    }