Что происходит
Так как 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