4

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?

Patrick Hofman
  • 153,850
  • 22
  • 249
  • 325
KDecker
  • 6,928
  • 8
  • 40
  • 81
  • The answer marked as duplicate is not the answer to this question. This question must be reopened. – Matthew Watson Nov 17 '15 at 15:49
  • 1
    I've *reopened* the question since it's about *floating point* overflow, not *integer* overflow – Dmitry Bychenko Nov 17 '15 at 15:50
  • *underflow* is the hardest problem in the question, in C++ you can put something like that http://stackoverflow.com/questions/15655070/how-to-detect-double-precision-floating-point-overflow-and-underflow – Dmitry Bychenko Nov 17 '15 at 15:55

2 Answers2

5

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.

Patrick Hofman
  • 153,850
  • 22
  • 249
  • 325
  • 2
    `checked` doesn't work with `Double`; you'll get `+Inf` (or `-Inf`) on overflow, no exception will be thrown – Dmitry Bychenko Nov 17 '15 at 15:43
  • Fixed! Didn't realize it was a double... @DmitryBychenko – Patrick Hofman Nov 17 '15 at 15:49
  • Regarding the bonus question, with the example of going from Celsius to Kelvin. Adding 273 to `Double.MaxValue` still results in `Double.MaxValue`, even if it didn't I would plan to set the value to `MaxValue` if it hit `PositiveInfinity`. But I guess I am still curious the reason why adding a comparatively small value to `MaxValue` does not result in `PositiveInfinity` Can you shed some light on this? – KDecker Nov 17 '15 at 16:58
  • Not sure but I guess it doesn't overflow since the 100 number isn't significant enough to have any effect on the number. – Patrick Hofman Nov 17 '15 at 17:23
  • This is dumb question. But if I use a `Func` within a `checked` block, will it still throw the exception if an overflow occurs when evaluation the `Func`? – KDecker Nov 17 '15 at 17:42
  • Actually it seems that this is not the case. It also bring up its own issues as I outline in this related SO question: http://stackoverflow.com/questions/33763897/determine-if-a-checked-operation-using-func-on-integers-resulted-in-an-overflow – KDecker Nov 17 '15 at 19:47
  • 1
    In floating-point, “underflow” does not mean “producing -inf”, and is **not** caught by `double.IsInfinity`. https://en.wikipedia.org/wiki/Arithmetic_underflow – Pascal Cuoq Nov 17 '15 at 22:37
1

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.

Matthew Watson
  • 104,400
  • 10
  • 158
  • 276