自己实现各种进制相互转换

本文自己实现了2、8、10、16进制数的相互转换。实际中很少用到或者直接用api,所以大神老鸟请绕行。

有兴趣的朋友也可以自己先写写,当做练习,仅此而已。

ok, 直接进入主题。先说一下各进制转换的算法(百度一下也ok的)。

 

算法:

一、10 进制数是平时所用到的,先从它开始。10进制转换为其它进制的数,用到的是【辗转相除取余法】。简单的说,就是该数一直除以进制数(例如2进制就除以2),然后取余数,一直到结果为0。依次由下往上取余数就是结果。

例如:5(10进制),转换为2进制,进行上述过程,得到的余数分别是:1、0、1, 那么结果就是:101(二进制)。对于 8和16进制,也是同样的过程。需要注意的是,对于16进制,10-15 分别表示为:A-E。

二、非10进制转换为10进制数。用到的是【位乘法】(名称是乱起的,只是为了与除法相对)。简单的说,公式就是:i * base^(j-1),i: 第j位上的数, base:进制  j: 第j位。例如:101(2进制),运用公式后就是:1 * 2^2 + 0 * 2^1 + 1 * 2^0 = 5(十进制)。

三、其它进制的相互转换。既然有了10进制这个“中间人”,其它的转换只要通过这个中间人就可以了。实际上转换的过程也很简单,例如8进制转2进制,就是“一分为三”;16进制转2进制,就是“一分为四”;相反的过程就是“三位合一”、“四位合一”。

需要注意的是:上述计算过程都是针对整数部分,如果是小数部分,计算就不一样了。

现在我们来看看小数部分的计算。

对于一、小数部分的计算是:小数部分 * base 取整数,小数部分再继续 * base,再得到整数... 一直到小数部分为0。例如10进制数:0.5,转为8进制是:

0.5 * 8 = 4.0 ; 也就是:4。

对于二、小数部分的计算是:i * base^(-j)。 例如2进制数,0.11,小数部分的计算是:1 * 2^(-1) + 1 * 2^(-2)。

 so,上面就是基本的转换过程,文字表达起来肯定没那么清晰,有兴趣的朋友可以百度,图文并茂,更好理解。

 

实现:

我们先来看一下利用.net提供的功能是如何实现的,很简单,就2行代码,如下:

1
2
3
4
5
static string SystemConvertUseAPI(string value, int from, int to)
{
    int temp = Convert.ToInt32(value, from);
    return Convert.ToString(temp, to);
}

不过Convert自带的转换有一个缺点,就是无法计算小数和负数,.net3.5 下测试的,不知道高版本的可不可以。

下面是我自己的实现过程,(核心部分就是与10进制的相互转换),如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
public static class SystemConvert
{
    public static string ConvertValue(string value, int from, int to)
    {
        EnsureArguments(value, from, to);
        char c = value[0];
        string[] values = GetValues(value);
        string result = string.Empty;
        if (from == 10)
            result = TenToOthers(values, to);
        else if (to == 10)
            result = OthersToTen(values, from);
        else
            result = OthersToOthers(values, from, to);
 
        return c == '-' ? c.ToString() + result : result;
    }
 
    /// <summary>
    /// 检查参数
    /// </summary>
    /// <param name="value"></param>
    /// <param name="from"></param>
    /// <param name="to"></param>
    private static void EnsureArguments(string value, int from, int to)
    {
        if (value == null || value.Trim() == string.Empty)
            throw new ArgumentNullException("value");
        if (!(from == 10 || from == 2 || from == 8 || from == 16))
            throw new ArgumentException("from 指定的基数不正确!");
        if (!(to == 10 || to == 2 || to == 8 || to == 16))
            throw new ArgumentException("to 指定的基数不正确!");
 
        string pattern = string.Empty;
        Regex regex = null;
        if (from == 2)
            pattern = @"^(\-|\+?)[01]+(.{0,1}[01]+)?$";
        else if (from == 8)
            pattern = @"^(\-|\+?)[01234567]+(.{0,1}[01234567]+)?$";
        else if (from == 10)
            pattern = @"^(\-|\+?)[0123456789]+(.{0,1}[0123456789]+)?$";
        else
            pattern = @"^(\-|\+?)[0123456789|abcdef|ABCDEF]+(.{0,1}[0123456789|abcdef|ABCDEF]+)?$";
 
        regex = new Regex(pattern);
        if (!regex.IsMatch(value))
            throw new ArgumentException("源字符串不符合" + from.ToString() + "进制规范");
    }
 
    /// <summary>
    /// 拆分字符串
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    private static string[] GetValues(string value)
    {
        value = value.Trim(new char[] { '+', '-', '0', '.' });
        return value.Split(new char[] { '.' });
    }
 
    private static int Format16Char2Number(string c)
    {
        switch (c.ToUpper())
        {
            case "A":
                return 10;
            case "B":
                return 11;
            case "C":
                return 12;
            case "D":
                return 13;
            case "E":
                return 14;
            case "F":
                return 15;
            default:
                return Convert.ToInt32(c);
        }
    }
 
    private static string Format16Number2Char(int number)
    {
        switch (number)
        {
            case 10:
                return "A";
            case 11:
                return "B";
            case 12:
                return "C";
            case 13:
                return "D";
            case 14:
                return "E";
            case 15:
                return "F";
            default:
                return number.ToString();
        }
    }
 
    /// <summary>
    /// 其它进制转换为10进制(位乘法)
    /// </summary>
    /// <param name="value"></param>
    /// <param name="from"></param>
    /// <returns></returns>
    private static string OthersToTen(string[] values, int from)
    {
        string result = string.Empty;
        string integer = values[0];
        string temp = string.Empty;
        int integerCurrent = 0;
        int integerResult = 0;
        int index = integer.Length - 1;
        bool is16 = from == 16;
        foreach (var c in integer)
        {
            temp = c.ToString();
            integerCurrent = is16 ? Format16Char2Number(temp) : Convert.ToInt32(temp);
            integerResult += integerCurrent * (int)Math.Pow((double)from, (double)index);
            index--;
        }
 
        if (values.Length <= 1)
        {
            return integerResult.ToString();
        }
        else
        {
            string decimaler = values[1];
            double decimalerCurrent = 0.0;
            double decimalerResult = 0.0;
            index = -1;
            foreach (var c in decimaler)
            {
                temp = c.ToString();
                decimalerCurrent = is16 ? Format16Char2Number(temp) : Convert.ToDouble(temp);
                decimalerResult += decimalerCurrent * Math.Pow((from), (double)index);
                index--;
            }
            return (integerResult + decimalerResult).ToString();
        }
    }
 
    /// <summary>
    /// 10进制转换为其它进制(辗转相除法)
    /// </summary>
    /// <param name="values"></param>
    /// <param name="to"></param>
    /// <returns></returns>
    private static string TenToOthers(string[] values, int to)
    {
        int integerCurrent = Convert.ToInt32(values[0]);
        int remainder = 1;
        bool is16 = to == 16;
        string integerResult = string.Empty;
        while (integerCurrent > 0)
        {
            remainder = integerCurrent % to;
            integerResult = (is16 ? Format16Number2Char(remainder) : remainder.ToString()) + integerResult;
            integerCurrent = integerCurrent / to;
        }
        if (values.Length <= 1)
        {
            return integerResult;
        }
        else
        {
            double decimalerCurrent = Convert.ToInt32(values[1]) / Math.Pow(10.0, (double)values[1].Length);
            int decimalerInt = 0;
            double decimalerDec = decimalerCurrent;
            string decimalerResult = string.Empty;
            string[] strArr;
            while (decimalerDec != 0)
            {
                decimalerCurrent = decimalerDec * to;
                //拆分double,得到整数和小数部分
                strArr = decimalerCurrent.ToString().Split(new char[] { '.' });
                decimalerInt = Convert.ToInt32(strArr[0]);
                if (strArr.Length > 1)
                    decimalerDec = Convert.ToDouble(strArr[1]) / (Math.Pow(10.0, (double)strArr[1].Length));
                else
                    decimalerDec = 0;
                decimalerResult += is16 ? Format16Number2Char(decimalerInt) : decimalerInt.ToString();
                //这里默认精确到32位,可以加个参数指定
                if (decimalerResult.Length > 32)
                    break;
            }
            return integerResult + "." + decimalerResult;
        }
    }
 
    /// <summary>
    /// 其它进制互转。以10进制为中间值即可
    /// </summary>
    /// <param name="values"></param>
    /// <param name="from"></param>
    /// <param name="to"></param>
    /// <returns></returns>
    private static string OthersToOthers(string[] values, int from, int to)
    {
        string to10 = OthersToTen(values, from);
        values = to10.Split(new char[] { '.' });
        return TenToOthers(values, to);
    }
}

顺带一句,【程序设计】,个人觉得最重要的是“设计”二字。在写代码前,我们需要理清逻辑,想好实现的过程;当设计好了,代码写起来会更快、bug 也会更少,测试起来也更容易。所以,碰到一个问题或需求,切记不要马上就敲代码。

posted @   我是攻城狮  阅读(811)  评论(1编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
点击右上角即可分享
微信分享提示