【问题标题】:Convert a "big" Hex number (string format) to a decimal number (string format) without BigInteger Class将“大”十六进制数(字符串格式)转换为没有 BigInteger 类的十进制数(字符串格式)
【发布时间】:2013-06-02 16:29:34
【问题描述】:

如何转换“大”十六进制数(字符串格式):

EC851A69B8ACD843164E10CFF70CF9E86DC2FEE3CF6F374B43C854E3342A2F1AC3E30C741CC41E679DF6D07CE6FA3A66083EC9B8C8BF3AF05D8BDBB0AA6CB3EF8C5BAA2A5E531BA9E28592F99E0FE4F95169A6C63F635D0197E325C5EC76219B907E4EBDCD401FB1986E4E3CA661FF73E7E2B8FD9988E753B7042B2BBCA76679 P>

转为十进制数(字符串格式):

166089946137986168535368849184301740204613753693156360462575217560130904921953976324839782808018277000296027060873747803291797869684516494894741699267674246881622658654267131250470956587908385447044319923040838072975636163137212887824248575510341104029461758594855159174329892125993844566497176102668262139513 P>

不使用BigInteger 类(因为我的应用程序应该支持没有.NET Framework 4 的机器)?

【问题讨论】:

  • AFAIK,没有简单的方法可以做到这一点。不过,我很想被证明是错误的。
  • 编写自己的BigInteger 实现?只使用现有的东西(例如BigInteger)将是最简单的。
  • 我投票结束,因为您排除了明显的解决方案,而这个决定背后没有任何理由。过于本地化。
  • @spender 你不认为建议对此进行编辑比建议“关闭”更好吗?
  • 对我来说似乎是一个完全合理的问题。可能太长了不能全部加载到内存中(:-S)

标签: c# hex biginteger base


【解决方案1】:

这是一个快速而简单的实现,可以处理任意大的数字。这个实现的目的是简单,而不是性能;因此,如果要在生产场景中使用,应该对其进行大幅优化。

编辑:根据 Dan Byström 的逆向实现进一步简化 decimal-to-hex conversion

static string HexToDecimal(string hex)
{
    List<int> dec = new List<int> { 0 };   // decimal result

    foreach (char c in hex)
    {
        int carry = Convert.ToInt32(c.ToString(), 16);   
            // initially holds decimal value of current hex digit;
            // subsequently holds carry-over for multiplication

        for (int i = 0; i < dec.Count; ++i)
        {
            int val = dec[i] * 16 + carry;
            dec[i] = val % 10;
            carry = val / 10;
        }

        while (carry > 0)
        {
            dec.Add(carry % 10);
            carry /= 10;
        }
    }

    var chars = dec.Select(d => (char)('0' + d));
    var cArr = chars.Reverse().ToArray();
    return new string(cArr);
}

【讨论】:

  • 为什么dec 列表中以0 开头?
  • @TimothyShields:它的意思是十进制结果的初始值,但在十六进制输入非空的所有情况下都是多余的。我会删除它。
  • 你测试了哪个字符串?该代码为 OP 的编号生成正确的结果。
  • 啊,对不起。不知道命令行输入有限制,正在从 OP 的输入中截断两个字符串。
  • 大部分功劳归功于Dan Byström;我只是扭转了他的转变。很高兴帮助:-)
【解决方案2】:

我刚刚将 Douglas 的代码翻译成 VBA

Function HexToDecimal(ByVal sHex As String) As String

    Dim dec() As Long
    ReDim dec(0 To 0) As Long

    Dim lCharLoop As Long
    For lCharLoop = 1 To Len(sHex)

        Dim char As String * 1
        char = Mid$(sHex, lCharLoop, 1)

        Dim carry As Long
        carry = Val("&h" & char)

        Dim i As Long
        For i = 0 To UBound(dec)
            Dim lVal As Long
            lVal = dec(i) * 16 + carry
            dec(i) = lVal Mod 10
            carry = lVal \ 10
        Next i

        While (carry > 0)
            ReDim Preserve dec(0 To UBound(dec) + 1) As Long
            dec(UBound(dec)) = carry Mod 10
            carry = carry \ 10
        Wend
    Next

    For lCharLoop = UBound(dec) To LBound(dec) Step -1
        Dim sDecimal As String
        sDecimal = sDecimal & Chr$(48 + dec(lCharLoop))

    Next

    HexToDecimal = sDecimal

End Function

Private Sub TestHexToDecimal()

    Debug.Assert HexToDecimal("F") = "15"
    Debug.Assert HexToDecimal("4") = CStr(Val("&H4"))
    Debug.Assert HexToDecimal("10") = CStr(Val("&H10"))
    Debug.Assert HexToDecimal("20") = CStr(Val("&H20"))
    Debug.Assert HexToDecimal("30") = CStr(Val("&H30"))
    Debug.Assert HexToDecimal("40") = CStr(Val("&H40"))
    Debug.Assert HexToDecimal("44") = CStr(Val("&H44"))
    Debug.Assert HexToDecimal("FF") = "255"
    Debug.Assert HexToDecimal("FFF") = "4095"
    Debug.Assert HexToDecimal("443") = CStr(Val("&H443"))
    Debug.Assert HexToDecimal("443C1") = "279489"
    Debug.Assert HexToDecimal("443C1CE20DFD592FB374D829B894BBE5") = "90699627342249584016268008583970733029"

    Debug.Assert HexToDecimal("EC851A69B8ACD843164E10CFF70CF9E86DC2FEE3CF6F374B43C854E3342A2F1AC3E30" & _
    "C741CC41E679DF6D07CE6FA3A66083EC9B8C8BF3AF05D8BDBB0AA6CB3EF8C5BAA2A5" & _
    "E531BA9E28592F99E0FE4F95169A6C63F635D0197E325C5EC76219B907E4EBDCD401FB1" & _
    "986E4E3CA661FF73E7E2B8FD9988E753B7042B2BBCA76679") = _
    "1660899461379861685353688491843017402046137536931563604625752175601309049219" & _
    "5397632483978280801827700029602706087374780329179786968451649489474169926767" & _
    "4246881622658654267131250470956587908385447044319923040838072975636163137212" & _
    "8878242485755103411040294617585948551591743298921259938445664971761026682621" & _
    "39513"

End Sub

也是statman.info Hexadecimal Conversion for large numbers的基准

【讨论】:

    【解决方案3】:

    您可以使用 IntX 库,因为它应该适用于 .Net 2.0 及更高版本。从页面上关于BigInteger的描述:

    所以在内部 System.Numerics.BigInteger 似乎使用标准 任意算术算法,我不担心 IntX 库,因为由于它使用了 FHT,它对于 非常大的整数。

    许可证相当宽松,但值得首先阅读以确保它没问题。

    我没有使用过这个库,但粗略看了一下源代码,这应该是你需要做的全部

    string dec = new IntX(myHex, 16).ToString();
    

    如果不想自己编译代码,可以通过 Nuget 安装。

    【讨论】:

      【解决方案4】:

      一种简单的方法是使用支持您的 .NET 版本的大数字库。我推荐GnuMpDotNet,它使用了优秀的GMP library。默认情况下,它以 .NET 3.5 为目标,但您可以将其更改为 .NET 2.0 而不会破坏任何内容(只需删除引用和引用新事物的 using 语句),因为它不使用 .NET 3.5 中的任何内容。下面是一个使用 GnuMpDotNet 的例子:

      BigInt e = new BigInt(hexString, 16);
      string decimalStr = e.ToString();
      

      【讨论】:

        【解决方案5】:

        在这里看我的回答:https://stackoverflow.com/a/18231860/2521214

        值得一看

        • 基于字符串的转换(仅受可用内存限制)
        • dec->十六进制和十六进制
        • 没有使用 bigint/bigreal 库
        • 支持定点字符串格式(无指数)

        【讨论】:

          【解决方案6】:

          我刚刚将 Douglas 代码翻译成 PHP:

          function BigNumberHexToDecimal($hex)
          {
              $dec = array(0);
              $hexLen = strlen($hex);
              for($h=0;$h<$hexLen;++$h)
              {
                  $carry = hexdec($hex[$h]);
                  for ($i = 0; $i < count($dec); ++$i)
                  {
                      $val = $dec[$i] * 16 + $carry;
                      $dec[$i] = $val % 10;
                      $carry = (int)($val / 10);
                  }
                  while ($carry > 0)
                  {
                      $dec[] = $carry % 10;
                      $carry = (int)($carry / 10);
                  }
              }
          
              return join("", array_reverse($dec));
          }
          

          【讨论】:

            【解决方案7】:

            我刚刚将 Douglas 代码翻译成 JAVA:

            public static String HexToDec(String hex) {
                List<Integer> dec = new ArrayList<Integer>();
            
                for (int k = 0; k < hex.length(); k++) {
                    String c = hex.charAt(k) + "";
                    int carry = Integer.parseInt(c, 16);
            
                    for (int i = 0; i < dec.size(); ++i) {
                        int val = dec.get(i) * 16 + carry;
                        dec.set(i, val % 10);
                        carry = val / 10;
                    }
            
                    while (carry > 0) {
                        dec.add(carry % 10);
                        carry /= 10;
                    }
                }
            
                int[] out = new int[dec.size()];
                for (int i = 0; i < dec.size(); i++) {
                    out[i] = dec.get(i).intValue();
                }
            
                return arrayToDecString(reverseArray(out));
            
            }
            
            public static String arrayToDecString(int[] data) {
            
                String str = "";
                for (int i = 0; i < data.length; i++) {
                    str += data[i] + "";
                }
                return str;
            }
            
            public static int[] reverseArray(int[] data) {
                for (int i = 0; i < data.length / 2; i++) {
                    int temp = data[i];
                    data[i] = data[data.length - i - 1];
                    data[data.length - i - 1] = temp;
                }
                return data;
            }
            

            【讨论】:

              【解决方案8】:

              我刚刚将 Douglas 代码翻译成 Delphi/Pascal:

              function HexToDecimal(const Hex: string): string;
              var
                dec: TList;
                I: Integer;
                carry: Cardinal;
                c: Char;
                val: Integer;
              begin
                Result := '';
                dec := TList.Create;
                try
                  dec.Add(Pointer(0));          // decimal result
              
                  for c in Hex do begin
                    carry := StrToInt('$' + c); // initially holds decimal value of current hex digit;
                                                // subsequently holds carry-over for multiplication
                    for I := 0 to dec.Count -1 do begin
                      val := Integer(dec[I]) * 16 + carry;
                      dec[I] := Pointer(Integer(val mod 10));
                      carry := val div 10;
                    end;
              
                    while carry > 0 do begin
                      dec.Add(Pointer(Integer(carry mod 10)));
                      carry := carry div 10;
                    end;
                  end;
              
                  for I := 0 to dec.Count -1 do begin
                    val := Integer(dec[I]);
                    Result := IntToStr(val) + Result;
                  end;
                finally
                  dec.Free;
                end;
              end;
              
              procedure Test;
              var
                S: string;
              begin
                S := HexToDecimal('FF'); // 255
                S := HexToDecimal('FFF'); // 4095
                S := HexToDecimal('443C1'); // 279489
                S := HexToDecimal('443C1CE20DFD592FB374D829B894BBE5'); // "90699627342249584016268008583970733029"
                S := 'EC851A69B8ACD843164E10CFF70CF9E86DC2FEE3CF6F374B43C854E3342A2F1AC3E30' +
                  'C741CC41E679DF6D07CE6FA3A66083EC9B8C8BF3AF05D8BDBB0AA6CB3EF8C5BAA2A5' +
                  'E531BA9E28592F99E0FE4F95169A6C63F635D0197E325C5EC76219B907E4EBDCD401FB1' +
                  '986E4E3CA661FF73E7E2B8FD9988E753B7042B2BBCA76679';
                S := HexToDecimal(S); // "166089946137986168535368849184301740204613753693156360462575217560130904921953976324839782808018277000296027060873747803291797869684516494894741699267674246881622658654267131250470956587908385447044319923040838072975636163137212887824248575510341104029461758594855159174329892125993844566497176102668262139513"
              end;
              

              【讨论】:

                猜你喜欢
                • 2022-07-08
                • 1970-01-01
                • 1970-01-01
                • 2012-08-15
                • 1970-01-01
                • 2013-05-21
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多