Add long and Ulug in C #

The api I'm using has an ulong field (I can't change this). I need to configure this field for the amount of long (maybe int ). However, I cannot add these tags: Operator '+' is ambiguous on operands of type 'ulong' and 'long' .

I cannot convert long to ulong because I lose sign, I cannot convert ulong to long because I could lose part of the value.

Ultimately, I want to try to tune the value if it causes a wrapper that I want to return false , rather than complete the tune. If this does not complete, I want to finish the setup and return true; I can do this part, but only if I can find a way to combine these two fields in the first place.

 public ulong Value; public bool AdjustValue(long amount) { // Operator '+' is ambiguous on operands of type 'ulong' and 'long' ulong adjustValue = Value + amount; if (amount < 0 && adjustValue > Value) return false; if (amount > 0 && adjustValue < Value) return false; Value = adjustValue; return true; } 

How can i solve this?

+5
source share
2 answers

For readability, you may prefer the sentence in the comment:

 adjustValue = Value; if (amount < 0) adjustValue -= (ulong)(-amount); else adjustValue += (ulong)amount; 

This clearly shows how you expect math to work.

However, & hellip;

The representation of integers in almost every modern hardware CPU is two additions. One of the reasons is that mathematics using two additional binary numbers has a very nice property: you get the same binary representation for addition and subtraction, regardless of whether you have signed or unsigned values.

This means that you can simply change the adjustment value to ulong to make your addition. According to C # language rules, a translation will simply reinterpret the binary representation of the signed value as unsigned. And adding an unsigned value will have exactly the same effect as if you added a signed value with the same binary representation.

Here is an example of code that shows that this works:

 static void Main(string[] args) { ulong[] values = { ulong.MinValue, ulong.MaxValue, long.MaxValue }; long[] adjust = { 0, 1, -1, long.MinValue, long.MaxValue }; for (int i = 0; i < values.Length; i++) { for (int j = 0; j < adjust.Length; j++) { ulong value = values[i]; bool result = AdjustValue(adjust[j], ref value); Console.WriteLine($"{values[i]} + {adjust[j]} = {values} (overflow: {!result})"); } } } static bool AdjustValue(long amount, ref ulong value) { ulong adjustValue = value + (ulong)amount; if (amount < 0 && adjustValue > value) return false; if (amount > 0 && adjustValue < value) return false; value = adjustValue; return true; } 

Note. By default, math operations are performed without verification. However, there is a compiler that can change this. If you compile your code with this switch turned on, forcing checked arithmetic operations, you need to wrap this in an unchecked block to avoid getting overflow exceptions.

+4
source

Someone will hate this answer, but you can use the decimal data type, as it is capable of storing 28-29 significant digits, and 2 ^ 64 has only 20 digits.

Naturally, using a floating point data type leads to a small overhead in terms of performance, but on the other hand, this code is very easy to read and may have better branch prediction / pipelining than a solution requiring if .

 public static ulong Add(this ulong baseValue, long offset) { decimal adjustedValue = (decimal)baseValue + offset; return (ulong)adjustedValue; } 

If you overfill the system, the system will be pretty decent to throw an ArgumentOutOfRangeException , but you can also flip it:

 public static ulong Add(this ulong baseValue, long offset) { decimal adjustedValue = (decimal)baseValue + offset; if (adjustedValue > ulong.MaxValue) throw new ArgumentOutOfRangeException("Too big to fit!"); if (adjustedValue < ulong.MinValue) throw new ArgumentOutOfRangeException("Too small to fit!"); return (ulong)adjustedValue; } 
0
source

Source: https://habr.com/ru/post/1264214/


All Articles