英文:
Storing deltas for Unsigned Longs
问题
我正在编写一个类,其中包含一些 `ulong` 数据类型的度量属性
class Metrics {
public ulong Memory
public ulong Handles
public ulong Calls
}
我使用 `ulong` 的原因是因为这些值是无符号的,而有符号类型的容量将不足够。
但我还创建了另一个该类的实例来存储这些值的增量,即上次检查和当前检查之间的变化。
我遇到的问题是有时数字会减少,因此增量是负值,但我不能将其存储在 `ulong` 中。
即使我将 Delta 声明为普通的 LONG,如果数字从0上升到 ulong 的最大值,它仍然不会适合并且会引发错误。
在了解这一点的情况下,我应该如何存储 ulong 的增量值呢?
class myData {
public Metrics Deltas
public Metrics Data
ulong myValue = ulong.MaxValue;
Deltas.Calls = (myValue - Data.Calls);
Data.Calls = myValue;
// 增量将是 +MaxValue
myValue = 0;
Deltas.Calls = (myValue - Data.Calls);
Data.Calls = myValue;
// 增量将是 -MaxValue,无符号,无法存储
}
<details>
<summary>英文:</summary>
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
}
</details>
# 答案1
**得分**: 4
Adding/subtracting two 64-bit numbers produces a 65-bit result, so just use [Int128][1] 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
```csharp
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);
}
英文:
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);
}
答案2
得分: 2
尝试使用 BigInteger
using System;
using System.Numerics;
public struct Metrics {
public BigInteger Memory { get; set; }
public BigInteger Handles { get; set; }
public BigInteger Calls { get; set; }
}
public class Program
{
public static void Main()
{
Metrics deltas = new Metrics();
Metrics data = new Metrics();
Console.WriteLine("data.Calls: " + data.Calls);
BigInteger myValue = UInt64.MaxValue;
Console.WriteLine("myValue (UInt64.MaxValue): " + myValue);
deltas.Calls = myValue - data.Calls;
Console.WriteLine("deltas.Calls (myValue-data.Calls): " + deltas.Calls);
data.Calls = myValue;
Console.WriteLine("data.Calls (myValue): " + data.Calls);
Console.WriteLine("\n");
Console.WriteLine("data.Calls: " + data.Calls);
myValue = 0;
Console.WriteLine("myValue: " + myValue);
deltas.Calls = myValue - data.Calls;
Console.WriteLine("deltas.Calls (myValue-data.Calls): " + deltas.Calls);
data.Calls = myValue;
Console.WriteLine("data.Calls (myValue): " + data.Calls);
}
}
结果:
data.Calls: 0
myValue (UInt64.MaxValue): 18446744073709551615
deltas.Calls (myValue-data.Calls): 18446744073709551615
data.Calls (myValue): 18446744073709551615
data.Calls: 18446744073709551615
myValue: 0
deltas.Calls (myValue-data.Calls): -18446744073709551615
data.Calls (myValue): 0
英文:
Try use BigInteger
using System;
using System.Numerics;
public struct Metrics {
public BigInteger Memory { get; set; }
public BigInteger Handles { get; set; }
public BigInteger Calls { get; set; }
}
public class Program
{
public static void Main()
{
Metrics deltas = new Metrics();
Metrics data = new Metrics();
Console.WriteLine("data.Calls: " + data.Calls);
BigInteger myValue = UInt64.MaxValue;
Console.WriteLine("myValue (UInt64.MaxValue): " + myValue);
deltas.Calls = myValue - data.Calls;
Console.WriteLine("deltas.Calls (myValue-data.Calls): " + deltas.Calls);
data.Calls = myValue;
Console.WriteLine("data.Calls (myValue): " + data.Calls);
Console.WriteLine("\n");
Console.WriteLine("data.Calls: " + data.Calls);
myValue = 0;
Console.WriteLine("myValue: " + myValue);
deltas.Calls = myValue - data.Calls;
Console.WriteLine("deltas.Calls (myValue-data.Calls): " + deltas.Calls);
data.Calls = myValue;
Console.WriteLine("data.Calls (myValue): " + data.Calls);
}
}
Result:
data.Calls: 0
myValue (UInt64.MaxValue): 18446744073709551615
deltas.Calls (myValue-data.Calls): 18446744073709551615
data.Calls (myValue): 18446744073709551615
data.Calls: 18446744073709551615
myValue: 0
deltas.Calls (myValue-data.Calls): -18446744073709551615
data.Calls (myValue): 0
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论