Description
Background and motivation
I want to calculate the difference between two values as a non-negative max - start
number.
TFrom start
, and TFrom max
define a range whose length is from 0
to int.MaxValue - 1
.
0 <= length < int.MaxValue
When TFrom
is wider than int
, calculate the length simply as length = int.CreateTruncating(end - start)
, because the difference end - start
is always positive.
When TFrom
is narrower than int
and has a sign, the difference between them can be a negative number, which is difficult to convert to a positive value. For example when TFrom
is sbyte
and start = -128; max = 127
then length = 128 + 127 = 255 = -1 (signed byte)
.
It isn't not easy to convert TFrom(-1) to positive TTo(255)
int.CreateTruncating(TFrom(-1))
creates int(-1)
uint.CreateTruncating(TFrom(-1))
creates uint.MaxValue. This made the sign propagation!
So I made the next workaround code.
internal static int StartMaxCount(T start, T max)
{
int count = int.CreateTruncating(max - start);
if (count < 0)
count = int.CreateTruncating(max) - int.CreateTruncating(start);
return count;
}
API Proposal
namespace System.Numerics
{
public interface INumberBase<TSelf> where TSelf : INumberBase<TSelf>?
{
static TSelf CreateTruncating<TOther>(TOther value, bool signPropagation) where TOther : INumberBase<TOther>;
protected static bool TryConvertFromTruncating<TOther>(TOther value, bool signPropagation, [MaybeNullWhen(false)] out TSelf result) where TOther : INumberBase<TOther>;
protected static bool TryConvertToTruncating<TOther>(TSelf value, bool signPropagation, [MaybeNullWhen(false)] out TOther result) where TOther : INumberBase<TOther>;
}
}
API Usage
// Range where TFrom is sbyte
TFrom start = -128;
TFrom max = 127;
// Calculate the correct length
int length = int.CreateTruncating(max - start, false);
See also
runtime/src/libraries/System.Linq/src/System/Linq/Range.cs
Lines 30 to 49 in e689e2a
Alternative Designs
No response
Risks
No response