Reputation: 7148
I have some classes within my application that represent physical units, for instance temperature. These classes have the ability to have some units associated with them and changed, such as Celcius and Kelvin. They also have user defined Max and Min values.
When I want to change units I get a conversion factor between the two given units and then alter the Min
, Max
, and Data
values within the class by performing some arithmetic operation with the conversion factor.
Double ConversionFactor = GetConversionFactor(curUnits, newUnits);
Units = newUnits;
Min *= ConversionFactor;
Max *= ConversionFactor;
Data *= ConversionFactor;
The issue I am having is that sometimes a user might allow the max and min values to be the MinValue
and MaxValue
of some type such as Double
. If a user were to change units that have a conversion factor larger than 1 this will result in overflow.
Is there a way in C# to detect if this overflow will happen for both overflow and underflow?
From what I can tell with some tests I think I just need to check that the result of the operation does not equal positive or negative infinity? If so I can then just set the value back to either MinValue
or MaxValue
.
Also, bonus question. In my testing I found that if I create a Double max = Double.MaxValue
and add something small like 100 to it. The value does not change.
Why is this? Is there some threshold between MaxValue
and PositiveInfinity
because the precision is so low at that large of value?
Upvotes: 4
Views: 2901
Reputation: 938
In addition to the previous answers:
They need one correction: if you type-case some value of a wider domain to the type of a more narrow domain, and the source value is Infinity
, this is not an overflow. For example:
static float CheckedConversion(double d) {
float result = (float)d;
if (float.IsInfinity(result) && !double.IsInfinity(d))
throw new //... throw some exception, for example
return result;
}
If you simply check up the result
for Infinity
, it would be correct if d
is PositiveInvinity
or NegativeInfinity
.
Upvotes: 0
Reputation: 109852
Floating point arithmetic does not throw exceptions.
Instead, you must perform the operation and then check the results, for example:
double d1 = double.MaxValue;
double d2 = double.MaxValue;
double d3 = d1*d2;
if (double.IsInfinity(d3))
Console.WriteLine("Infinity");
if (double.IsPositiveInfinity(d3))
Console.WriteLine("Positive Infinity");
d1 = double.MinValue;
d2 = double.MaxValue;
d3 = d1*d2;
if (double.IsInfinity(d3))
Console.WriteLine("Infinity");
if (double.IsNegativeInfinity(d3))
Console.WriteLine("Negative Infinity");
Note that double.IsInfinity(d)
will be true if either double.IsPositiveInfinity(d)
or double.IsNegativeInfinity()
is true.
As you have observed, adding a relatively small number to double.MaxValue
does not result in double.Infinity
. This is because of rounding - the value you're adding is way smaller than the value that can be represented for a double with an exponent so large.
Upvotes: 1
Reputation: 157136
If the variable is a double, you should check for Infinity
.
The best way to do that is by using double.IsInfinity
, which will check for both underflow and overflow (positive and negative infinity).
bool overflowed = double.IsInfinity(Min);
You can wrap that in an own extension method or so if you want to.
If the variable is an integer you can wrap the statement in a checked
block, which will cause an exception when the operation overflows. This isn't preventive, but it does the job.
checked
{
...
}
You can try...catch
that.
Upvotes: 5