2010-03-11 2 views
8

64 비트보다 큰 임의의 큰 배열을 C#에서 문자열로 표시된 10 진수로 변환하는 함수를 작성하려고합니다. 그것을하는 방법을 알아낼 수 없습니다. 예를 들어 다음과 같은 코드를바이트 배열을 한 자릿수의 문자열로 변환합니다.

...

Console.WriteLine(ConvertToString(
    new byte[] 
    { 
    0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 
    0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00 
    })); 

가 .. 인쇄한다

22774453838368691933757882222884355840 

내가 원하는 때문에, 단지에 대한 biginteger 같은 별도의 라이브러리를 사용하지 않으려는 그것은 간단하고 그것이 어떻게 작동 하는지를 이해하는 것을 좋아합니다.

+2

나는 BigInteger의 라이브러리를 사용에 충실하고, 단지 그것이 어떻게 작동하는지보기 위해 반사판을 사용합니다. 이 코드를 다시 작성하는 것은 매우 필요하지 않습니다. – Codesleuth

+0

그는 분명히 그 뒤에있는 방법을 배우기를 원합니다. – Skurmedel

답변

2

:

static string BytesToString(byte[] data) { 
    // Minimum length 1. 
    if (data.Length == 0) return "0"; 

    // length <= digits.Length. 
    var digits = new byte[(data.Length * 0x00026882/* (int)(Math.Log(2, 10) * 0x80000) */ + 0xFFFF) >> 16]; 
    int length = 1; 

    // For each byte: 
    for (int j = 0; j != data.Length; ++j) { 
     // digits = digits * 256 + data[j]. 
     int i, carry = data[j]; 
     for (i = 0; i < length || carry != 0; ++i) { 
      int value = digits[i] * 256 + carry; 
      carry = Math.DivRem(value, 10, out value); 
      digits[i] = (byte)value; 
     } 
     // digits got longer. 
     if (i > length) length = i; 
    } 

    // Return string. 
    var result = new StringBuilder(length); 
    while (0 != length) result.Append((char)('0' + digits[--length])); 
    return result.ToString(); 
} 
0

System.Decimal이 필요하십니까?

+0

아니, MSDN은 말한다 : "진수 값 유형은 긍정적 79,228,162,514,264,337,593,543,950,335 부정적인 79,228,162,514,264,337,593,543,950,335에 이르기까지 진수를 나타냅니다." – Martin

5

일부 지침 :

  1. 당신은 각 숫자에 대한 매트릭스에 하나 개의 공간을 수의 숫자를 저장해야합니다. 행렬이 비어 있습니다.
  2. 그런 다음 행렬의 곱셈을 저장하려면 행렬이 필요합니다. 너무 비어 있습니다.
  3. 지금 바이트마다, 당신은 :
    1. 먼저 해당 일시 자리에서 10 개 계수를 저장, 256에 의해 현재 수 행렬의 각 숫자를 곱하면 다음 자리 곱셈을 10로 나눈 수를 추가 할 수 있습니다.
    2. 임시 곱셈 행렬을 현재 숫자 행렬에 할당하십시오.
    3. 그런 다음 첫 번째 숫자에 바이트를 추가하십시오.
    4. 각 색인에 10 모듈을 저장하고 10으로 나눈 값을 다음 색인으로 전달하여 현재 행렬을 정정하십시오.
  4. 그런 다음 문자열의 각 숫자를 연결해야합니다.
  5. 문자열을 반환합니다.

필요에 따라 각 행렬을 확장하거나 전달 된 바이트 수에서 필요한 최대 크기를 결정하십시오.

편집, 상기 세 번째 단계 다음 예 :

값 = [를 0xAA, 0xbb 경계] 초기 전류 = [] 초기 온도 = []를 0xAA

함께

  1. Nothing으로 곱하다.
  2. 할당이 변경되지 않았습니다.
  3. 우리는 현재의 첫번째 값를 0xAA을 추가 = 현재 우리는 다음 값으로 열로 나눈 값 전달 만 계수를 저장 현재 수정 [170]
  4. :
    1. 1 자리 : 현재를 = [0] 전달 17.
    2. 두 번째 숫자 : 현재 = [0, 7] 통과 1.
    3. 세 번째 자리 : 현재 = [0, 7, 1] 전달할 값이 없으므로 프로세스가 종료됩니다. 256 0xbb 경계

      1. Multipli와 지금

  5. 각 숫자에 대해 수행 온도 및 수정을 절감 할 는
      에게
    1. 첫째 자리 : 온도 [0, 0 저장 = 다음 자리로.
    2. 두 번째 자리 : 보정 이전의 온도 = [0, 1792], 보정 후 온도 [= 0, 2], 179가 전달됩니다.
    3. 셋째 자리 : 온도 = [0, 2, 1 × 256 + 179 = 435] 보정 전의, 온도는 = [0, 2, 5, 43 보정 후 전달한다.
    4. 네째 자리 : 온도 = [0, 2, 5, 43] 앞서, 온도가 = [0, 2, 5, 3, 3
    5. 다섯째 자리 후 합격 : 온도 = [0, 2, 5, 3, 4] 보정 전후에 저장할 자리가 없기 때문에 곱셈은 끝납니다. 전류
  6. Assing 온도 : 전류 = [0, 2, 5, 3, 4; 온도 [η]
  7. 는 제 자리에 현재 값을 추가
    1. 첫째 자리 : 전류 = 7, 2 전류 = [187, 2, 5, 3, 4]
    2. 의 값을 정정 , 5, 3, 4], 18을 패스합니다.
    3. 두 번째 숫자 : 현재 = [7, 0, 5, 3, 4], 2를 전달합니다.
    4. 세 번째 자리 : 현재 = [7, 0, 7, 3, 4], 아무 것도 지나쳐서 추가가 끝나지 않습니다.

지금 우리는 결과 당신은 너무 C# BigInteger Class @ CodeProject 고급형 에서 살펴 작용을 이해하려는 43707.

+0

@Wilhelm : 귀하의 설명을 이해할 수 없다고 생각합니다 (하지만 작동하는 것처럼 들립니다) .. 2 바이트 (예 : 0xAA 및 0xBB)로 예를 들어 주시겠습니까? – Martin

+0

"matrix"는 나에게 잘못된 의미를 가지고 있습니다. 배열이나 목록이라고 부릅니다. –

+0

'n '바이트의 최대 자리수는'ceil (8 n log_10 (2))'입니다. 16.16 고정 소수점을 사용 :'(n * 0x00026882 + 0xFFFF) >> 16'. –

1

위해 연결할 필요가있다.

또한, 나는이 질문에 대한 필수 맨발하는 클래스를 제거했다. 그것은 더 이상 최적화 될 수 있습니다. :)

다음 코드를 복사하여 붙여 넣으십시오. @ Wilheim의 답변에 따라

using System; 

public class BigInteger 
{ 
    // maximum length of the BigInteger in uint (4 bytes) 
    // change this to suit the required level of precision. 

    private const int maxLength = 70; 


    private uint[] data = null;    // stores bytes from the Big Integer 
    public int dataLength;     // number of actual chars used 


    public BigInteger() 
    { 
     data = new uint[maxLength]; 
     dataLength = 1; 
    } 

    public BigInteger(long value) 
    { 
     data = new uint[maxLength]; 
     long tempVal = value; 

     dataLength = 0; 
     while (value != 0 && dataLength < maxLength) 
     { 
      data[dataLength] = (uint)(value & 0xFFFFFFFF); 
      value >>= 32; 
      dataLength++; 
     } 

     if (tempVal > 0)   // overflow check for +ve value 
     { 
      if (value != 0 || (data[maxLength - 1] & 0x80000000) != 0) 
       throw (new ArithmeticException("Positive overflow in constructor.")); 
     } 
     else if (tempVal < 0) // underflow check for -ve value 
     { 
      if (value != -1 || (data[dataLength - 1] & 0x80000000) == 0) 
       throw (new ArithmeticException("Negative underflow in constructor.")); 
     } 

     if (dataLength == 0) 
      dataLength = 1; 
    } 

    public BigInteger(ulong value) 
    { 
     data = new uint[maxLength]; 

     // copy bytes from ulong to BigInteger without any assumption of 
     // the length of the ulong datatype 

     dataLength = 0; 
     while (value != 0 && dataLength < maxLength) 
     { 
      data[dataLength] = (uint)(value & 0xFFFFFFFF); 
      value >>= 32; 
      dataLength++; 
     } 

     if (value != 0 || (data[maxLength - 1] & 0x80000000) != 0) 
      throw (new ArithmeticException("Positive overflow in constructor.")); 

     if (dataLength == 0) 
      dataLength = 1; 
    } 

    public BigInteger(BigInteger bi) 
    { 
     data = new uint[maxLength]; 

     dataLength = bi.dataLength; 

     for (int i = 0; i < dataLength; i++) 
      data[i] = bi.data[i]; 
    } 

    public BigInteger(byte[] inData) 
    { 
     dataLength = inData.Length >> 2; 

     int leftOver = inData.Length & 0x3; 
     if (leftOver != 0)   // length not multiples of 4 
      dataLength++; 


     if (dataLength > maxLength) 
      throw (new ArithmeticException("Byte overflow in constructor.")); 

     data = new uint[maxLength]; 

     for (int i = inData.Length - 1, j = 0; i >= 3; i -= 4, j++) 
     { 
      data[j] = (uint)((inData[i - 3] << 24) + (inData[i - 2] << 16) + 
          (inData[i - 1] << 8) + inData[i]); 
     } 

     if (leftOver == 1) 
      data[dataLength - 1] = (uint)inData[0]; 
     else if (leftOver == 2) 
      data[dataLength - 1] = (uint)((inData[0] << 8) + inData[1]); 
     else if (leftOver == 3) 
      data[dataLength - 1] = (uint)((inData[0] << 16) + (inData[1] << 8) + inData[2]); 


     while (dataLength > 1 && data[dataLength - 1] == 0) 
      dataLength--; 

     //Console.WriteLine("Len = " + dataLength); 
    } 

    public override string ToString() 
    { 
     return ToString(10); 
    } 

    public string ToString(int radix) 
    { 

     string charSet = "ABCDEF"; 
     string result = ""; 

     BigInteger a = this; 

     BigInteger quotient = new BigInteger(); 
     BigInteger remainder = new BigInteger(); 
     BigInteger biRadix = new BigInteger(radix); 

     if (a.dataLength == 1 && a.data[0] == 0) 
      result = "0"; 
     else 
     { 
      while (a.dataLength > 1 || (a.dataLength == 1 && a.data[0] != 0)) 
      { 
       singleByteDivide(a, biRadix, quotient, remainder); 

       if (remainder.data[0] < 10) 
        result = remainder.data[0] + result; 
       else 
        result = charSet[(int)remainder.data[0] - 10] + result; 

       a = quotient; 
      } 
     } 

     return result; 
    } 

    private static void singleByteDivide(BigInteger bi1, BigInteger bi2, 
             BigInteger outQuotient, BigInteger outRemainder) 
    { 
     uint[] result = new uint[maxLength]; 
     int resultPos = 0; 

     // copy dividend to reminder 
     for (int i = 0; i < maxLength; i++) 
      outRemainder.data[i] = bi1.data[i]; 
     outRemainder.dataLength = bi1.dataLength; 

     while (outRemainder.dataLength > 1 && outRemainder.data[outRemainder.dataLength - 1] == 0) 
      outRemainder.dataLength--; 

     ulong divisor = (ulong)bi2.data[0]; 
     int pos = outRemainder.dataLength - 1; 
     ulong dividend = (ulong)outRemainder.data[pos]; 

     if (dividend >= divisor) 
     { 
      ulong quotient = dividend/divisor; 
      result[resultPos++] = (uint)quotient; 

      outRemainder.data[pos] = (uint)(dividend % divisor); 
     } 
     pos--; 

     while (pos >= 0) 
     { 
      dividend = ((ulong)outRemainder.data[pos + 1] << 32) + (ulong)outRemainder.data[pos]; 
      ulong quotient = dividend/divisor; 
      result[resultPos++] = (uint)quotient; 

      outRemainder.data[pos + 1] = 0; 
      outRemainder.data[pos--] = (uint)(dividend % divisor); 
     } 

     outQuotient.dataLength = resultPos; 
     int j = 0; 
     for (int i = outQuotient.dataLength - 1; i >= 0; i--, j++) 
      outQuotient.data[j] = result[i]; 
     for (; j < maxLength; j++) 
      outQuotient.data[j] = 0; 

     while (outQuotient.dataLength > 1 && outQuotient.data[outQuotient.dataLength - 1] == 0) 
      outQuotient.dataLength--; 

     if (outQuotient.dataLength == 0) 
      outQuotient.dataLength = 1; 

     while (outRemainder.dataLength > 1 && outRemainder.data[outRemainder.dataLength - 1] == 0) 
      outRemainder.dataLength--; 
    } 



    public static void Main(string[] args) 
    { 

     BigInteger big = new BigInteger( new byte[] 
            { 
            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 
            0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00 
            }); 

     Console.WriteLine(big); 

    } 

} 
관련 문제