I have written this block of code, in an attempt to create a generic random array generator (quite an interesting approach, if I must say so myself)
public unsafe class RandomArray<T> : DynamicArray<T> where T : INumber<T> {
Type _type;
Random _r;
T _min;
T _max;
int _type_size;
T _MaxValue;
T _MinValue;
private void init(int capacity) {
_MaxValue = (T)typeof(T).GetField("MaxValue").GetValue(null);
_MinValue = (T)typeof(T).GetField("MinValue").GetValue(null);
// T ratio = T
// _MaxValue & _MinValue allow us to determine the ratio
_r = new Random();
generate(capacity);
_size = capacity;
}
private void generate(int capacity) {
// take into account _min & _max
byte[] b = new byte[capacity*_type_size+1];
_r.NextBytes(b);
fixed (byte* ptr_b = b) {
T* t = (T*)ptr_b;
for (int i = 0; i < capacity; i++) {
_data[i] = *(t+i);
}
};
}
public RandomArray(int capacity, T min, T max) : base(capacity+1) {
_type_size = Marshal.SizeOf(min);
_type = min.GetType();
_min = min;
_max = max;
init(capacity);
}
}
The code is a combination of concepts taken from the following sources:
To interpret bytes as generic type T
:
Converting random bytes to integers within a specified range
To get the MinValue
/MaxValue
of a Generic primitive numeric type:
How do I get the max and min value of a generic number type in c#
However, the problem that I face is that I cannot seem to come up with a mechanism to set the bounds of the min & max elements/limit the range of the random numbers generated because of some complications related to casting.
What would be the simplest technique to mimic:
_min + (*(t+i) / ratio);
where ratio would be computed as (_MaxValue - _MinValue) / (_max - _min)
It's obvious that _MaxValue - _MinValue
will be type overflow, outside the bounds of the generic T
, so I have tried using BigIntegers
to do this, but I can't figure out exactly how this should work.
The problem is that I can't figure out how I would cast the BigInteger result back to a generic type T
as I have done in most the body of the code.
How would I handle the case of calculating the ratio so that it is well defined given the complications that arise from type casting?
To change type of BigInteger
is not straight forward.
I would suggest using Convert.ChangeType
method, but it won't accept BigInteger
, as it does not implement IConvertible
.
However, BigInteger
has casts to numeric types, so I would pick big numeric type (to prevent any information loss), let's use decimal
. When BigInteger
is cast to decimal, then we can use mentioned method Convert.ChangeType
.
Here's sample code:
Console.WriteLine(Get<int>());
Console.WriteLine(Get<long>());
Console.WriteLine(Get<decimal>());
T Get<T>() where T : struct, IConvertible
{
BigInteger b = 1;
var t = (T)Convert.ChangeType((decimal)b, typeof(T));
return t;
}
UPDATE
For the other way around (converting to BigInteger
) here's code example:
BigInteger GetBigInt<T>(T input) where T : struct
{
BigInteger t = Convert.ToInt64(input);
return t;
}