Using C#, I have a few custom classes where I need to be able to detect integer overflows and return a default minimum or maximum value depending on if the overflow was due to the result being over the maximum value or under the minimum value. I can't seem to find a suggestion on how to detect the "type" of overflow that occurs anywhere.
The classes are divided between two general types: ones that use signed values, and ones that use unsigned values.
As an example, here is one of the classes that deals with Int32 values:
public class Stat32Tf : IStat32T<float>
{
#region fields
private int baseValue, baseAdjustment;
private float baseMultiplier;
#endregion
#region ctors
public Stat32Tf()
{
baseValue = 0;
baseAdjustment = 0;
baseMultiplier = 1f;
}
public Stat32Tf(int baseValue, int baseAdjustment = 0, float baseMultiplier = 1f)
{
this.baseValue = baseValue;
this.baseAdjustment = baseAdjustment;
this.baseMultiplier = baseMultiplier;
}
#endregion
#region properties
public int BaseValue
{
get
{
return baseValue;
}
set
{
baseValue = value;
}
}
public int BaseAdjustment
{
get
{
return baseAdjustment;
}
set
{
baseAdjustment = value;
}
}
public float BaseMultiplier
{
get
{
return BaseMultiplier;
}
set
{
baseMultiplier = value;
}
}
public int TruncValue
{
get
{
return (int)Value;
}
}
public float Value
{
get
{
return (baseValue + baseAdjustment) * baseMultiplier;
}
}
#endregion
}
As you can see, the idea of the class is to hold a base value, an adjustment value, and a multiplier value, and return the aggregate value in the Value property. (The TruncValue property just, as it suggests, returns the truncated whole value, dropping any fractional values).
The goal is to handle overflows in the "get" accessor of the Value property and, if the result is over the max int value, return int.MaxValue and if it is under the min value, return int.MinValue, all without throwing the actual overflow error. The part that's making it tricky for me is that the adjustment values and multipliers could be negative values as well (as per the design requirement).
What is a safe way to achieve this? I have not been able to find any resources that address this kind of situation. I'm guessing some sort of arithmetic algorithm will need to be used to determine of results will be over or under.
There are only a limited number of cases where it could underflow:
If baseValue and baseAdjustment are both negative -> If Int.MinValue - baseAdjustment > baseValue then you have an underflow.
If baseValue + baseAjustment is negative and baseMultiplier is positive -> If an overflow exception is raised, then it can only be an underflow.
If baseValue + baseAdjustment is positive but baseMultiplier is negative -> If an overflow exception is raised, then it can only be an underflow.
If you want to avoid raising/catching exception, then it might be a bit more complicated (you may want to cast the result as long and compare it against Int.MaxValue; that way it'll only raise an exception if the result goes over Long.MaxValue).
Floats are pretty big. Are you expecting the get value to overflow or do you expect the cast to int to overflow? If it's just the cast something similar to the following code might work.
Although you might need some additional handling for the edge cases.
Edit - I played around with this in some code and found some behavior that I didn't expect, but apparently it is in the specification.
For example,
You really might need to up cast everything into a double and then check to see if the result is greater than or less than an int.
So it might look something like this: