Преобразование "большого" шестнадцатеричного числа (строковый формат) в десятичное число (строковый формат) без класса BigInteger
Как преобразовать "большое" шестнадцатеричное число (в строковом формате):
EC851A69B8ACD843164E10CFF70CF9E86DC2FEE3CF6F374B43C854E3342A2F1AC3E30C741CC41E679DF6D07CE6FA3A66083EC9B8C8BF3AF05D8BDBB0AA6CB3EF8C5BAA2A5E531BA9E28592F99E0FE4F95169A6C63F635D0197E325C5EC76219B907E4EBDCD401FB1986E4E3CA661FF73E7E2B8FD9988E753B7042B2BBCA76679
в десятичное число (в строковом формате):
166089946137986168535368849184301740204613753693156360462575217560130904921953976324839782808018277000296027060873747803291797869684516494894741699267674246881622658654267131250470956587908385447044319923040838072975636163137212887824248575510341104029461758594855159174329892125993844566497176102668262139513
без использования BigInteger
Класс (как мое приложение должно поддерживать машины без.NET Framework 4)?
9 ответов
Вот быстрая и грязная реализация, которая может работать с произвольно большими числами. Целью этой реализации является простота, а не производительность; таким образом, его следует резко оптимизировать, если он будет использоваться в производственном сценарии.
Редактировать: упрощено далее для реализации обратного десятичного числа в шестнадцатеричное преобразование Дана Быстрёма:
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);
}
Я только что перевел код Дугласа на 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 Шестнадцатеричное Преобразование для больших чисел
Я только что перевел код Дугласа на 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;
}
Я только что перевел код Дугласа на 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));
}
Я только что перевел код Дугласа на 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;
Переведенный код Дугласа в Qt:
QByteArray convertHexToDecimal(const QByteArray &hex)
{
QList<int> dec;
for (int i = 0; i < hex.count(); i++) {
int carry = hex.mid(i, 1).toInt(nullptr, 16);
for (int j = 0; j < dec.count(); ++j) {
int val = dec[j] * 16 + carry;
dec[j] = val % 10;
carry = val / 10;
}
while (carry > 0) {
dec.append(carry % 10);
carry /= 10;
}
}
QByteArray chars;
foreach (int d, dec) {
chars.prepend((char)('0' + d));
}
return chars;
}
Самый простой способ - использовать библиотеку больших чисел, которая поддерживает вашу версию.NET. Я бы порекомендовал GnuMpDotNet, который использует отличную библиотеку GMP. По умолчанию он нацелен на.NET 3.5, но вы можете изменить его на.NET 2.0, ничего не нарушая (просто удалите ссылки и using
заявление, которое относится к новым вещам), так как он не использует ничего из.NET 3.5. Вот пример использования GnuMpDotNet:
BigInt e = new BigInt(hexString, 16);
string decimalStr = e.ToString();
Вы можете использовать библиотеку IntX, так как она должна работать с.Net 2.0 и выше. Из описания на странице в отношении BigInteger
:
Поэтому внутренне System.Numerics.BigInteger, похоже, использует стандартные произвольные арифметические алгоритмы, и я не беспокоюсь о библиотеке IntX, поскольку благодаря использованию FHT она может быть в разы быстрее для действительно больших целых чисел.
Лицензия довольно либеральная, но стоит сначала прочитать ее, чтобы убедиться, что она в порядке.
Я не использовал эту библиотеку, но из беглого взгляда на исходный код это все, что вам нужно сделать
string dec = new IntX(myHex, 16).ToString();
Если вы не хотите компилировать код самостоятельно, вы можете установить его через Nuget.
Посмотрите на мой ответ здесь: /questions/43630952/kak-preobrazovat-standartnoe-tseloe-v-strokovom-formate-v-shestnadtsaterichnyij-format-s/43630957#43630957
стоит посмотреть
- преобразования на основе строк (ограничено только свободной памятью)
- dec-> hex и hex<-dec включены
- не используется bigint / bigreal lib
- поддержка форматов строк с фиксированной запятой (без показателей степени)