首页 > 解决方案 > 转换时如何解析 long.MaxValue 和 ulong.MaxValue

问题描述

我试图解析 long 和 ulong 的最大值,但它失败了。怎么做?

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

value是 Int64.MaxValue 但类型value是双精度。

标签: c#long-integerulong

解决方案


发生了什么

由于double具有~15-17 位的精度,因此不可能对以字符串准确表示的方式double分配的 a 进行字符串化(19 位)。Int64.MaxValue9223372036854775807Int64.MaxValue

解决方案

A. 使用Int64

不要将整数值存储为double.

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

B. 软糖

使用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

推荐阅读