存储无符号长整型的增量值

huangapple go评论71阅读模式
英文:

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&#39;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) =&gt; a;
    public static Delta operator -(Delta a) =&gt; 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 &lt; 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 &gt; max.magnitude) // overflow
        {
            sign = !sign;
        }
        
        return new Delta(max - min, sign);
    }
    public static Delta operator -(Delta a, Delta b) =&gt; a + (-b);
    
    public static bool operator ==(Delta a, Delta b)
    {
        return a.magnitude == b.magnitude &amp;&amp; a.sign == b.sign;
    }
    public static bool operator !=(Delta a, Delta b) =&gt; !(a == b);
    
    public static bool operator &gt;(Delta a, Delta b)
    {
        return a.sign == b.sign ? a.sign ^ (a.magnitude &gt; b.magnitude) b.sign;
    }
    public static bool operator &lt;(Delta a, Delta b) =&gt; !(a &gt; b);
    
    public override string ToString()
    {
        return sign ? $&quot;-{magnitude}&quot; : $&quot;{magnitude}&quot;;
    }
}

 // 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(&quot;data.Calls: &quot; + data.Calls);

		BigInteger myValue = UInt64.MaxValue;
		Console.WriteLine(&quot;myValue (UInt64.MaxValue): &quot; + myValue);

		deltas.Calls = myValue - data.Calls;	
		Console.WriteLine(&quot;deltas.Calls (myValue-data.Calls): &quot; + deltas.Calls);

		data.Calls = myValue;
		Console.WriteLine(&quot;data.Calls (myValue): &quot; + data.Calls);
	   
		
		Console.WriteLine(&quot;\n&quot;);
				
		Console.WriteLine(&quot;data.Calls: &quot; + data.Calls);

		myValue = 0;
		Console.WriteLine(&quot;myValue: &quot; + myValue);

		deltas.Calls = myValue - data.Calls;
		Console.WriteLine(&quot;deltas.Calls (myValue-data.Calls): &quot; + deltas.Calls);

		data.Calls = myValue;
		Console.WriteLine(&quot;data.Calls (myValue): &quot; + 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

huangapple
  • 本文由 发表于 2023年6月13日 08:51:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/76461090.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定