Durga S
Durga S

Reputation: 295

How to parse long.MaxValue and ulong.MaxValue when doing conversion

I have tried to parse the maxvalue of long and ulong but it fails. How to do that?

Int64.TryParse(value.ToString(), out resultInt)

value is Int64.MaxValue but the type of the value is double.

Upvotes: 0

Views: 1254

Answers (1)

tmaj
tmaj

Reputation: 35037

What's happening

Since double has the precision of ~15-17 digits it's not possible to stringify a double that was assigned Int64.MaxValue in a way that the string would represent exactly 9223372036854775807 (Int64.MaxValue, 19 digits).

Solution

A. Use Int64

Don't store integral values as double.

var l1 = long.MaxValue;
var l2 = long.Parse(l1.ToString());
Console.WriteLine( $"Diff: {l2-l1}");
// Diff: 0

B. Fudge

With ToString("F0") (and few other formats) it's possible to get quite close; just 1 above Int64.MaxValue (9223372036854775808).

You could try to trim the double string.

public static (long L, bool IsHack) GetLongUpToMaxValue(string str) {
    try
    {
        return (long.Parse(str, NumberStyles.Any), false);
    } 
    catch( OverflowException )
    {
        var ul = ulong.Parse(str, NumberStyles.Any);
        if((ul - long.MaxValue) == 1) return (long.MaxValue, true);
        throw;
    }
}

Test code

public static void Main(string[] args)
{
 Console.WriteLine($"{"SRC", -25}{"STR", -25}{"DIFF", -10}{"HACK?", -10}");
 foreach(long l in new[]{Int64.MaxValue, Int64.MaxValue-1, Int64.MaxValue-2, Int64.MaxValue-100, Int64.MaxValue-1000, Int64.MinValue, Int64.MinValue+1, Int64.MinValue+2, 1000, -1000, 0})
 {
     double d = l;
     var dStr = d.ToString("F0");// F,G19
     (long l2, bool isHack) = GetLongUpToMaxValue(d.ToString("F0"));
     Console.WriteLine($"{l2, -25}{dStr, -25}{l - l2, -10}{isHack}");
 }

Output

// .NETCoreApp,Version=v3.0
SRC                      STR                      DIFF      HACK?
9223372036854775807      9223372036854775808      0         True
9223372036854775807      9223372036854775808      -1        True
9223372036854775807      9223372036854775808      -2        True
9223372036854775807      9223372036854775808      -100      True
9223372036854774784      9223372036854774784      23        False
-9223372036854775808     -9223372036854775808     0         False
-9223372036854775808     -9223372036854775808     1         False
-9223372036854775808     -9223372036854775808     2         False
1000                     1000                     0         False
-1000                    -1000                    0         False
0                        0                        0         False

Examples of different formats

Here are some examples for few ToString formats.

var l1 = Int64.MaxValue;
Console.WriteLine($"Int64.MaxValue: {l1}");
double d = l1;

foreach(var x in new []{"C", "E", "F", "F0", "G", "G15", "G30", "N", "P", "R", "##########################"}) {
    var dStr = d.ToString(x);
    Console.WriteLine($"{x} {dStr}");

    try { Console.WriteLine($"\t long diff: {long.Parse(dStr, NumberStyles.Any) - long.MaxValue}");} 
    catch (Exception ex) { Console.WriteLine($"\t long.Parse: {ex.Message}");};

    try { Console.WriteLine($"\t ulong diff: {ulong.Parse(dStr, NumberStyles.Any) - long.MaxValue}");} 
    catch (Exception ex) { Console.WriteLine($"\t ulong.Parse: {ex.Message}");};

    Console.WriteLine();
}

Output

// .NETCoreApp,Version=v3.0
Int64.MaxValue: 9223372036854775807
C $9,223,372,036,854,775,808.00
         long.Parse: Value was either too large or too small for an Int64.
         ulong diff: 1

E 9.223372E+018
         long diff: -36854775807
         ulong diff: 18446744036854775809

F 9223372036854775808.00
         long.Parse: Value was either too large or too small for an Int64.
         ulong diff: 1

F0 9223372036854775808
         long.Parse: Value was either too large or too small for an Int64.
         ulong diff: 1

G 9.223372036854776E+18
         long.Parse: Value was either too large or too small for an Int64.
         ulong diff: 193

G15 9.22337203685478E+18
         long.Parse: Value was either too large or too small for an Int64.
         ulong diff: 4193

G30 9223372036854775808
         long.Parse: Value was either too large or too small for an Int64.
         ulong diff: 1

N 9,223,372,036,854,775,808.00
         long.Parse: Value was either too large or too small for an Int64.
         ulong diff: 1

P 922,337,203,685,477,580,800.00%
         long.Parse: Input string was not in a correct format.
         ulong.Parse: Input string was not in a correct format.

R 9.223372036854776E+18
         long.Parse: Value was either too large or too small for an Int64.
         ulong diff: 193

########################## 9223372036854780000
         long.Parse: Value was either too large or too small for an Int64.
         ulong diff: 4193

Upvotes: 1

Related Questions