An api I am using has a ulong
field (I can't change this). I need to adjust this field by the a long
amount (could be an int
too). However I can't add these togeather: Operator '+' is ambiguous on operands of type 'ulong' and 'long'
.
I can't convert the long
to a ulong
because I will lose the sign, I can't convert the ulong
to a long
because I could lose part of the value.
Ultimately I want to attempt to adjust the value, if it would cause a wrap I want to return false
and not finish the adjustment. If it doesn't wrap I want to finish the adjustment and return true; I can do this part, but only if I can figure out a a way to add the two fields together 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?
To take input " long long int " and output " long long int " in C is : long long int n; scanf("%lld", &n); printf("%lld", n);
You can store a bigger value in ulong than long , but no negative numbers allowed. A long value is stored in 64-bit,with its first digit to show if it's a positive/negative number. while ulong is also 64-bit, with all 64 bit to store the number. so the maximum of ulong is 2(64)-1, while long is 2(63)-1.
%lu. Unsigned int or unsigned long. %lli or %lld.
Simply write long long int for a signed integer, or unsigned long long int for an unsigned integer. To make an integer constant of type long long int , add the suffix ` LL ' to the integer. To make an integer constant of type unsigned long long int , add the suffix ` ULL ' to the integer.
For readability, you may prefer the suggestion in the comment:
adjustValue = Value;
if (amount < 0)
adjustValue -= (ulong)(-amount);
else
adjustValue += (ulong)amount;
This makes clear how you expect the math to work.
However…
The representation of integers in practically every modern hardware CPU is two's complement. One of the reasons is that math using two's complement binary numbers has a very nice property: you get the same binary representation for addition and subtraction whether you're dealing with signed or unsigned values.
This means that you can just cast the adjustment value to ulong
to do your addition. According to the C# language rules, the cast will simply reinterpret the signed value's binary representation as unsigned. And adding the unsigned value will have exactly the same effect as if you'd added a signed value with that same binary representation.
Here's a code example that shows this working:
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 runtime are unchecked. However, there is a compiler switch that can change this. If you are compiling your code with that switch enabled, forcing checked arithmetic operations, you will need to wrap the above in an unchecked
block to avoid getting overflow exceptions.
Someone's going to hate this answer, but you could use the decimal data type, since it is capable of storing 28-29 significant digits and 2^64 only has 20 digits.
Naturally using a floating point data type incurs a bit of overhead in terms of performance, but on the other hand this code is really easy to read, and may have better branch prediction/pipelining than a solution that requires if
.
public static ulong Add(this ulong baseValue, long offset)
{
decimal adjustedValue = (decimal)baseValue + offset;
return (ulong)adjustedValue;
}
If you overflow, the system will throw a decent enough ArgumentOutOfRangeException
, but you could also roll your own:
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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With