位置記數法:(dₙ...d₁d₀)₍ᵦ₎ = Σ dᵢ × bⁱ,從最低位 (右) 到最高位 (左) 累加。
public static class BaseConverter
{
///
/// 任意進制字串 (2-36) 轉十進制 long
///
public static long ToDecimal(string value, int @base)
{
if (string.IsNullOrWhiteSpace(value)) throw new ArgumentException("值不可為空", nameof(value));
if (@base < 2 || @base > 36) throw new ArgumentOutOfRangeException(nameof(@base), "支援進制 2-36");
value = value.Trim().ToUpperInvariant();
bool negative = value.StartsWith("-");
if (negative) value = value[1..];
long result = 0;
foreach (char c in value)
{
int digit = CharToValue(c);
if (digit < 0 || digit >= @base) throw new FormatException($"字元 '{c}' 不屬於 {@base} 進制");
result = checked(result * @base + digit); // checked 捕獲溢位
}
return negative ? -result : result;
}
///
/// 十進制 long 轉任意進制字串 (2-36)
///
public static string FromDecimal(long value, int @base)
{
if (@base < 2 || @base > 36) throw new ArgumentOutOfRangeException(nameof(@base), "支援進制 2-36");
if (value == 0) return "0";
bool neg = value < 0;
ulong v = neg ? (ulong)(-value) : (ulong)value;
var chars = new List();
while (v > 0)
{
int rem = (int)(v % (ulong)@base);
chars.Add(ValueToChar(rem));
v /= (ulong)@base;
}
if (neg) chars.Add('-');
chars.Reverse();
return new string(chars.ToArray());
}
private static int CharToValue(char c) => c switch
{
>= '0' and <= '9' => c - '0',
>= 'A' and <= 'Z' => c - 'A' + 10,
_ => -1
};
private static char ValueToChar(int v) => v switch
{
< 10 => (char)('0' + v),
< 36 => (char)('A' + v - 10),
_ => '?'
};
}
// 二進制
Console.WriteLine(BaseConverter.ToDecimal("11001", 2)); // 25
Console.WriteLine(BaseConverter.FromDecimal(25, 2)); // 11001
// 八進制
Console.WriteLine(BaseConverter.ToDecimal("32007", 8)); // 13319
Console.WriteLine(BaseConverter.FromDecimal(13319, 8)); // 32007
// 十六進制
Console.WriteLine(BaseConverter.ToDecimal("A20F", 16)); // 41487
Console.WriteLine(BaseConverter.FromDecimal(41487, 16)); // A20F
// 36 進制 (0-9, A-Z)
Console.WriteLine(BaseConverter.ToDecimal("ZZ", 36)); // 1295
Console.WriteLine(BaseConverter.FromDecimal(1295, 36)); // ZZ
// Convert 類別 (僅支援 2, 8, 10, 16)
Convert.ToInt64("A20F", 16); // 41487
Convert.ToString(41487, 16); // "a20f" (小寫)
// BigInteger (任意進制、任意大小)
BigInteger.Parse("A20F", NumberStyles.HexNumber); // 41487
BigInteger.Parse("11001", NumberStyles.AllowHexSpecifier); // 需自行處理進制
| 坑點 | 現象 | 解決 |
|---|---|---|
| 溢位 | 超過 long.MaxValue 擲出 OverflowException | 用 BigInteger 或自行實作任意精度 |
| 大小寫 | 十六進制 A-F 大小寫不一 | 統一 ToUpperInvariant() |
| 前綴 | 輸入含 0x, 0b, # | 預處理移除前綴 |
| 負數補碼 | 輸入為二進制補碼字串 | 需先判斷符號位再轉換 |
通用進制轉換核心在於「字元→數值」映射與「乘基數加權」迴圈。實務上優先使用 Convert (基礎進制) 或 BigInteger (大數/任意進制);自行實作適合教學、嵌入式無標準庫、或需特定格式輸出 (如固定寬度、前綴、分隔符) 的場景。