Как разобрать long.MaxValue и ulong.MaxValue при выполнении преобразования - PullRequest
0 голосов
/ 30 октября 2019

Я попытался разобрать maxvalue long и ulong, но это не удалось. Как это сделать?

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

value - это Int64.MaxValue, но тип value - двойной.

1 Ответ

1 голос
/ 30 октября 2019

Что происходит

Так как double имеет точность ~ 15-17 цифр , невозможно определить double, который был назначен Int64.MaxValue таким образом, чтострока будет точно представлять 9223372036854775807 (Int64.MaxValue, 19 цифр).

Решение

A. Используйте Int64

Не сохраняйте интегральные значения как double.

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

B. Fudge

С ToString("F0") (и несколькими другими форматами) можно подойти довольно близко;только на 1 Int64.MaxValue (9223372036854775808).

Вы можете попытаться обрезать двойную строку.

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;
    }
}

Тестовый код

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}");
 }

Выход

// .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

Примеры различных форматов

Вот несколько примеров для нескольких ToString форматов.

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();
}

Вывод

// .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
...