Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can C#/.net parse exponential hex encoded floating point numbers from strings?

C++, Java all include the [-]0xh.hhhhp+/-d format in the syntax of the language, other languages like python and C99 have library support for parsing these strings (float.fromhex, scanf).

I have not, yet, found a way to parse this exact hex encoded exponential format in C# or using the .NET libraries.

Is there a good way to handle this, or a decent alternative encoding? (decimal encoding is not exact).

Example strings: 0x1p-8 -0xfe8p-12

Thank you

like image 347
Mike Buland Avatar asked Nov 15 '12 00:11

Mike Buland


2 Answers

Unfortunately, I don't know of any method built-in to .NET that compares to Python's float.fromhex(). So I suppose the only thing you can do is roll your own .fromhex() in C#. This task can range in difficulty from "Somewhat Easy" to "Very Difficult" depending on how complete and how optimized you'd like your solution to be.

Officially, the IEEE 754 spec allows for decimals within the hexadecimal coefficient (ie. 0xf.e8p-12) which adds a layer of complexity for us since (much to my frustration) .NET also does not support Double.Parse() for hexadecimal strings.

If you can constrain the problem to examples like you've provided where you only have integers as the coefficient, you can use the following solution using string operations:

public static double Parsed(string hexVal)
{
    int index = 0;
    int sign = 1;
    double exponent = 0d;

    //Check sign
    if (hexVal[index] == '-')
    {
        sign = -1;
        index++;
    }
    else if (hexVal[index] == '+')
        index++;
    //consume 0x
    if (hexVal[index] == '0')
    {
        if (hexVal[index+1] == 'x' || hexVal[index+1] == 'X')
            index += 2;
    }

    int coeff_start = index;
    int coeff_end = hexVal.Length - coeff_start;

    //Check for exponent
    int p_index = hexVal.IndexOfAny(new char[] { 'p', 'P' });
    if (p_index == 0)
        throw new FormatException("No Coefficient");
    else if (p_index > -1)
    {
        coeff_end = p_index - index;
        int exp_start = p_index + 1;
        int exp_end = hexVal.Length;
        exponent = Convert.ToDouble(hexVal.Substring(exp_start, exp_end - (exp_start)));
    }

    var coeff = (double)(Int32.Parse(hexVal.Substring(coeff_start, coeff_end), NumberStyles.AllowHexSpecifier));
    var result = sign * (coeff * Math.Pow(2, exponent));
    return result;
}

If you're seeking an identical function to Python's fromhex(), you can try your hand at converting the CPython implementation into C# if you'd like. I tried, but got in over my head as I'm not very familiar with the standard and had trouble following all the overflow checks they were looking out for. They also allow other things like unlimited leading and trailing whitespace, which my solution does not allow for.

My solution is the "Somewhat Easy" solution. I'm guessing if you really knew your stuff, you could build the sign, exponent and mantissa at the bit level instead of multiplying everything out. You could definitely do it in one pass as well, rather than cheating with the .Substring() methods.

Hopefully this at least gets you on the right track.

like image 81
JoshVarty Avatar answered Oct 10 '22 09:10

JoshVarty


I have written C# code for formatting and parsing numbers in the hexadecimal floating-point format described in IEEE 754r and supported by C99, C++11 and Java. The code is part of the BSD-licenced FParsec library for F# and is contained in a single file: https://bitbucket.org/fparsec/main/src/tip/FParsecCS/HexFloat.cs

The supported format is described a bit at http://www.quanttec.com/fparsec/reference/charparsers.html#members.floatToHexString

The test code (written in F#) can be found at https://bitbucket.org/fparsec/main/src/tip/Test/HexFloatTests.fs

like image 44
Stephan Tolksdorf Avatar answered Oct 10 '22 11:10

Stephan Tolksdorf