自己实现各种进制相互转换
本文自己实现了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 也会更少,测试起来也更容易。所以,碰到一个问题或需求,切记不要马上就敲代码。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?