如何将 gi-normous 整数(字符串格式)转换为十六进制格式? (C#)

Posted

技术标签:

【中文标题】如何将 gi-normous 整数(字符串格式)转换为十六进制格式? (C#)【英文标题】:How to convert a gi-normous integer (in string format) to hex format? (C#) 【发布时间】:2011-02-08 19:31:24 【问题描述】:

给定一个潜在的巨大整数值(C# 字符串格式),我希望能够生成它的十六进制等效值。普通方法在这里不适用,因为我们谈论的是任意大的数字,50 位或更多。我见过的技术使用这样的技术:

// Store integer 182
int decValue = 182;
// Convert integer 182 as a hex in a string variable
string hexValue = decValue.ToString("X");
// Convert the hex string back to the number
int decAgain = int.Parse(hexValue, System.Globalization.NumberStyles.HexNumber);

因为要转换的整数太大,所以不起作用。

例如,我需要能够像这样转换字符串:

843370923007003347112437570992242323

到它的十六进制等价物。

这些不起作用:

C# convert integer to hex and back again How to convert numbers between hexadecimal and decimal in C#?

【问题讨论】:

'%x' % 843370923007003347112437570992242323。哎呀!对不起,那是 Python。 ;-) 只是出于好奇,您是否需要将这些数字存储在字符串中?这似乎浪费了很多位。您可以将数字对存储在字节 (BCD) 中吗? 我收到的数字是小数。我的任务是将它们更改为十六进制。 你在数宇宙中的原子数量吗? 或者他在计算比尔盖茨的税单 【参考方案1】:

哦,这很简单:

        var s = "843370923007003347112437570992242323";
        var result = new List<byte>();
        result.Add( 0 );
        foreach ( char c in s )
        
            int val = (int)( c - '0' );
            for ( int i = 0 ; i < result.Count ; i++ )
            
                int digit = result[i] * 10 + val;
                result[i] = (byte)( digit & 0x0F );
                val = digit >> 4;
            
            if ( val != 0 )
                result.Add( (byte)val );
        

        var hex = "";
        foreach ( byte b in result )
            hex = "0123456789ABCDEF"[ b ] + hex;

【讨论】:

是的,这确实是一个非常好的解决方案,并且在追求性能时,这是一个比创建 BigInteger 对象更好的起点。但是为了可维护性,这会增加代码大小和复杂性。因此,如果您在非常紧密的循环或某种核心消息处理程序中使用它,我只会走这条路。但仍然 +1 用于提供基于循环的转换。 这是一块垫脚石。出于性能考虑,您显然不会使用 List,而是使用足够大的 byte[]。完成后,它 快速 是的,有多种方式,可以预先估计数组的最大宽度,直接使用char数组,只消耗需要的位数。而不是你可以从该结果数组的正确子集创建一个字符串。 你有没有分析过它是否比使用 BigInteger 的直接实现更快?对我来说,结果看起来就像一个穷人对大整数的实现。 这是一个很好的解决方案!【参考方案2】:

使用BigInteger 存储整数,然后在该对象上使用.ToString("X")。

例子:

var number = BigInteger.Parse("843370923007003347112437570992242323");
string hexValue = number.ToString("X");

但这仅限于 .NET 4 及更高版本。但是 Jens A. 指出了 BigInteger class on codeproject,该类包含一个名为 ToHexString 的方法,因此适用于 <.net>

【讨论】:

不错的尝试,但我仅限于 .NET 3.5 及以下版本 对于 NET 3.5 和更低版本有一个很好的 BigInteger 实现:codeproject.com/KB/cs/biginteger.aspx【参考方案3】:

正如 Jens 所说,看看 Code Project 上的 BigInt 实现。即使他们没有转换为十六进制的功能,您也可以轻松地write a function 自己做,只要这个 BigInt 有一个除法和模运算(我不认为它有一个模函数,所以你会还需要自己写modulo)

【讨论】:

【参考方案4】:

heh 很好的 dechex 转换解决方案到目前为止在 *** 上,...但是我需要(巨大的 int 。巨大的分数)几乎没有丢失任何精度,所以我用我已经完成的代码修改了我找到的所有代码和这是我可以分享的一些(没有大的 int/real lib 使用)

//---------------------------------------------------------------------------
AnsiString str_hex2dec(const AnsiString &hex)
    
    char c;
    AnsiString dec="",s;
    int i,j,l,ll,cy,val;
    int  i0,i1,i2,i3,sig;
    sig=+1; l=hex.Length();
    if (l)  c=hex[l]; if (c=='h') l--; if (c=='H') l--; 
    i0=0; i1=l; i2=0; i3=l;
    for (i=1;i<=l;i++)      // scan for parts of number
        
        char c=hex[i];
        if (c=='-') sig=-sig;
        if ((c=='.')||(c==',')) i1=i-1;
        if ((c>='0')&&(c<='9'))  if (!i0) i0=i; if ((!i2)&&(i>i1)) i2=i; 
        if ((c>='A')&&(c<='F'))  if (!i0) i0=i; if ((!i2)&&(i>i1)) i2=i; 
        if ((c>='a')&&(c<='f'))  if (!i0) i0=i; if ((!i2)&&(i>i1)) i2=i; 
        

    l=0; s=""; if (i0) for (i=i0;i<=i1;i++)
        
        c=hex[i];
             if ((c>='0')&&(c<='9')) c-='0';
        else if ((c>='A')&&(c<='F')) c-='A'-10;
        else if ((c>='a')&&(c<='f')) c-='A'-10;
        for (cy=c,j=1;j<=l;j++)
            
            val=(s[j]<<4)+cy;
            s[j]=val%10;
            cy  =val/10;
            
        while (cy>0)
            
            l++;
            s+=char(cy%10);
            cy/=10;
            
        
    if (s!="")
        
        for (j=1;j<=l;j++)  c=s[j]; if (c<10) c+='0'; else c+='A'-10; s[j]=c; 
        for (i=l,j=1;j<i;j++,i--)  c=s[i]; s[i]=s[j]; s[j]=c; 
        dec+=s;
        
    if (dec=="") dec="0";
    if (sig<0) dec="-"+dec;

    if (i2)
        
        dec+='.';
        s=hex.SubString(i2,i3-i2+1);
        l=s.Length();
        for (i=1;i<=l;i++)
            
            c=s[i];
                 if ((c>='0')&&(c<='9')) c-='0';
            else if ((c>='A')&&(c<='F')) c-='A'-10;
            else if ((c>='a')&&(c<='f')) c-='A'-10;
            s[i]=c;
            
        ll=((l*1234)>>10);  // num of decimals to compute
        for (cy=0,i=1;i<=ll;i++)
            
            for (cy=0,j=l;j>=1;j--)
                
                val=s[j];
                val*=10;
                val+=cy;
                s[j]=val&15;
                cy=val>>4;
                
            dec+=char(cy+'0');
            for (;;)
                
                if (!l) break;;
                if (s[l]) break;
                l--;
                
            if (!l) break;;
            
        

    return dec;
    
//---------------------------------------------------------------------------
AnsiString str_dec2hex(AnsiString dec)
    
    AnsiString hex=""; BYTE a,b;
    int  i,j,i0,i1,i2,i3,l,sig;
    sig=+1; l=dec.Length();
    i0=0; i1=l; i2=0; i3=l;
    for (i=1;i<=l;i++)      // scan for parts of number
        
        char c=dec[i];
        if (c=='-') sig=-sig;
        if ((c=='.')||(c==',')) i1=i-1;
        if ((c>='0')&&(c<='9'))  if (!i0) i0=i; if ((!i2)&&(i>i1)) i2=i; 
        
    if (i0) for (;i1>=i0;i1=j-1)// process integer part /16
        
        for (a=0,j=i0,i=i0;i<=i1;i++)
            
            a*=10; a+=dec[i]-'0';
            if (a<16)  if (j>i0) dec[j]='0'; j++;  continue; 
            b=a>>4; a=a&15;
            if (b>10)  dec[j]='1'; j++; b-=10; 
            dec[j]=b+'0'; j++;
            
        if ((!a)&&(hex=="")) continue;
        if (a<10) a+='0'; else a+='A'-10;
        hex=AnsiString(char(a))+hex;
        
    if (hex=="") hex="0";

    if ((i2)&&(i2<=i3))     // process fractional part *16
     for (hex+=".",j=i3-i2+2;j;j--)
        
        for (a=0,b=0,i=i3;i>=i2;i--)
            
            a=dec[i]-'0';
            b+=a<<4; dec[i]=(b%10)+'0'; b/=10;
            
        if (b<10) b+='0'; else b+='A'-10;
        hex+=char(b);
        
    if (sig<0) hex="-"+hex; hex+="h";
    return hex;
    
//---------------------------------------------------------------------------

附:如果您需要截断小数位(以格式化数字),则必须将截断部分的最高有效位四舍五入。

如果 digit >='5',则在 dec 模式下将 abs 向上舍入 如果数字 >='8',则在十六进制模式下将 abs 向上舍入

如果你想知道这条线是什么意思:

ll=((l*1234)>>10);  // num of decimals to compute

它计算与输入字符串精度匹配的小数位数(每个十六进制小数位数 1.205 个十进制小数位数)。我通过经验测量精度得到这个比率,每个数字的小数部分高达 1280 位。为简单起见 1e-l 的最大误差可以存储到 1e-(l+1)。这个比率几乎是恒定的(除了低小数位值(8 位)或最大值为 2 (

【讨论】:

以上是关于如何将 gi-normous 整数(字符串格式)转换为十六进制格式? (C#)的主要内容,如果未能解决你的问题,请参考以下文章

C语言如何将64位整数转字符串

C语言中字符串和整数小数相互转换的函数以及头文件

sqlserver中如何把数字转换成时间的格式?

Leetcode 13 罗马数字转整数

C#里如何将XML格式字符串转成XML文件?

LeetCode:字符串转整数(atoi)