Home > Software engineering >  Is there a way to detect the overflow-checking context in code?
Is there a way to detect the overflow-checking context in code?

Time:01-08

I'm working on an importer for LitJson, to import float values from ints, and doubles, and if overflow-checking is enabled, I want to wrap a potential overflow exception in a JsonException with a bit more information about the failure.

Right now my code looks like this, and I don't know if I need to/can check if the context is checked or not:

private static float DoubleFloatImporter(double value) {
    try
    {
        return (float)value;
    }
    catch (Exception ex)
    {
        throw new JsonException("Value is not a valid Single", ex);
    }
}

CodePudding user response:

You may be thinking of checked and unchecked contexts, but these are not relevant for your example, the explicit conversion (cast) from double to float (so from double-precision binary floating point to single-precision).

A finite double value may round to an infinite float value (either float.PositiveInfinity or float.NegativeInfinity).

For example DoubleFloatImporter(1.23e123). As a double, the input 1.23e123 will be represented as a finite value, but when cast to float, the nearest representable value will be interpreted as ∞.

Edit: As I say in comments, something like:

private static float DoubleFloatImporter(double value) {
    var converted = (float)value;
    if (!float.IsFinite(converted))
        throw new JsonException("Converted value would become infinite or not a number");
    return converted;
}

may suit your need.

CodePudding user response:

What about something like this:

static float DoubleFloatImporter(double value)
{
    if (double.IsPositiveInfinity(value))
    {
        return float.PositiveInfinity;
    }
    if (double.IsNegativeInfinity(value))
    {
        return float.NegativeInfinity;
    }
    if (value > Single.MaxValue || value < Single.MinValue)
    {
        throw new OverflowException($"'{value}' doesn't fit");
    }

    return (float)value; //Single.CreateChecked(value);
}

Some examples:

using System.Runtime.CompilerServices;

Convert(1.0);
Convert(double.MaxValue);
Convert(double.PositiveInfinity);
Convert(double.NegativeInfinity);
Convert((double)float.MaxValue   100);
Convert((double)float.MaxValue * 2);
Convert(double.NaN);

static void Convert(double v, [CallerArgumentExpression("v")] string arg1Exp = "?")
{
    try
    {
        var f = DoubleFloatImporter(v);
        Console.WriteLine($"{arg1Exp}  ->  {f}");
    }
    catch (Exception ex)
    {
        Console.WriteLine($"{arg1Exp}  ->  {ex.Message}");
    }
}

The output:

1.0  ->  1
double.MaxValue  ->  '1.7976931348623157E 308' doesn't fit
double.PositiveInfinity  ->  ∞
double.NegativeInfinity  ->  -∞
(double)float.MaxValue   100  ->  3.4028235E 38
(double)float.MaxValue * 2  ->  '6.805646932770577E 38' doesn't fit
double.NaN  ->  NaN
  • Related