I am writing a class that has a bunch of metric properties of ulong
data type
class Metrics {
public ulong Memory
public ulong Handles
public ulong Calls
}
The reason I use ulong
is because it's a fact that those values are unsigned and the capacity of signed will not be enough.
But I also initiate another instance of this class to store Deltas of those values, the change between the last check and the current.
The problem I am having is that sometimes the number can go down, thus the delta is a negative value, but I cannot store it on the ulong
.
Even if I declare the Delta as a regular LONG, if number goes up to the ulong max from 0 it will not fit and will throw an error.
How could I accomplish storing the delta value of a ulong knowing this?
class myData {
public Metrics Deltas
public Metrics Data
ulong myValue = ulong.MaxValue;
Deltas.Calls = (myValue - Data.Calls);
Data.Calls = myValue;
// Delta will be +MaxValue
myValue = 0;
Deltas.Calls = (myValue - Data.Calls);
Data.Calls = myValue;
// Delta will be -MaxValue, unsigned, cannot store it
}
Adding/subtracting two 64-bit numbers produces a 65-bit result, so just use Int128 if you use .NET Core 7.0 Preview 5 or newer. And don't use class
if you just need to store data like this, a struct
or record
would be far better because they can live on stack
struct Metrics {
public Int128 Memory
public Int128 Handles
public Int128 Calls
}
class myData {
public Metrics Deltas
public Metrics Data
Int128 myValue = ulong.MaxValue;
Deltas.Calls = myValue - Data.Calls;
Data.Calls = myValue;
myValue = 0;
Deltas.Calls = myValue - Data.Calls;
Data.Calls = myValue;
}
If you're on an old .NET framework then the most efficient solution is to implement your own 65-bit data type. It should be very simple because for printing and sorting purposes multiplication and division won't be needed. You just need to implement +
/-
and comparison operators like this
public readonly struct Delta
{
private readonly ulong magnitude;
private readonly bool sign; // true: negative
public Delta(ulong magn, bool sgn)
{
sign = sgn;
magnitude = magn;
}
public Delta(ulong a)
{
sign = false;
magnitude = a;
}
public static Delta operator +(Delta a) => a;
public static Delta operator -(Delta a) => new Delta(a.magnitude, !a.sign);
public static Delta operator +(Delta a, Delta b)
{
if (a.sign == b.sign)
{
var m = a.magnitude + b.magnitude;
if (m < a.magnitude) // overflow
{
sign = !sign;
}
return new Delta(m, a.sign);
}
var max = Math.Max(a.magnitude, b.magnitude);
var min = Math.Min(a.magnitude, b.magnitude);
var sign = a.sign;
var m = max.magnitude - min.magnitude;
if (m > max.magnitude) // overflow
{
sign = !sign;
}
return new Delta(max - min, sign);
}
public static Delta operator -(Delta a, Delta b) => a + (-b);
public static bool operator ==(Delta a, Delta b)
{
return a.magnitude == b.magnitude && a.sign == b.sign;
}
public static bool operator !=(Delta a, Delta b) => !(a == b);
public static bool operator >(Delta a, Delta b)
{
return a.sign == b.sign ? a.sign ^ (a.magnitude > b.magnitude) b.sign;
}
public static bool operator <(Delta a, Delta b) => !(a > b);
public override string ToString()
{
return sign ? $"-{magnitude}" : $"{magnitude}";
}
}
// Get delta of a and b
public Delta GetDelta(ulong a, Delta ulong b)
{
return Delta(a) - Delta(b);
}