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

本文自己实现了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行代码,如下:

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

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

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

    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 也会更少,测试起来也更容易。所以,碰到一个问题或需求,切记不要马上就敲代码。

时间: 2024-10-15 00:51:48

自己实现各种进制相互转换的相关文章

C# byte和10进制、16进制相互转换

原文:C# byte和10进制.16进制相互转换 var SRMP = new byte[4]; Array.Copy(Encoding.UTF8.GetBytes(1.ToString("x2")), SRMP, Encoding.UTF8.GetBytes(1.ToString("x2")).Length); Array.Copy(Encoding.UTF8.GetBytes((j + 1).ToString("x2")), 0, SRMP,

PHP进制转换[实现2、8、16、36、64进制至10进制相互转换]

自己写了一个PHP进制转换程序,一个类吧,第一次写这个东东,写这个东东,在处理文本文件时能用得到. 可以实现: 10进制转换2.8.16.36.62进制2.8.16.36.62进制转换10进制 有点要注意下,2.8.16进制转换时,使用的是系统的自己的函数. 所以,不管怎么高精度转换值可能大于2147483646. 另外, 32进制低精转换,最大值:2147483646: 32进制高精转换,最大值:77309411327: 64进制高精转换,最大值:133143986175. jinzhi.ph

sql 进制转换,支持93内的进制相互转换

功能:实现在SQL内进制的互相转换,支持从2 - 93进制内的转换,若需要支持其他字符,可以自定义@ym变量实现扩充 1 -- ============================================= 2 -- Author: bwch 3 -- Create date: 2014年9月30日10:32:47 4 -- Description: 把一个数字转换成指定进制,最大支持93进制,也可在Function内扩充@ym实现其他的转换 5 -- ===============

Delphi - 10进制16进制相互转换

10进制转16进制 使用IntToHex可以实现十进制到十六进制的转换,注意这里的参数有两个,第一个表示需要被转换的10进制数,第二个表示转换后用几位来显示16进制数. 代码如下: function OctToHex(iValue, iBit: Integer): String; begin Result := IntToHex(iValue, iBit); end; 16进制转10进制 使用StrToInt可以实现16进制到10进制的转换. 代码如下: function HexToOct(hV

超级(无限)大的 --- 整型10进制数据与16进制数据相互转换

<html> <title>超级(无限)大的 --- 整型10进制数据与16进制数据相互转换</title> <head> <meta charset="utf-8"/> <meta name="keywords" content="数据压缩算法,超过整数表示范围的大数据算术运算,大进制数据互相转换" /> <meta name="keywords"

java 16进制与字符串直接相互转换

java 16进制与字符串直接相互转换 CreationTime--2018年7月12日09点39分 Author:Marydon 1.16进制转换成字符串 /** * 16进制直接转换成为字符串 * @explain * @param hexStr 16进制字符串 * @return String */ public static String fromHexString(String hexString) { // 用于接收转换结果 String result = ""; // 转

16进制串hex与ASCII字符串相互转换

提供两个函数,方便十六进制串与ASCII 字符串之间的相互转换,使用函数需要注意的是返回的串是在堆上通过 calloc 分配的,所以,记得使用完返回值释放该块,并且将指向该块的指针 =NULL . char *chstohex ( char* chs ) { char hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8','9', 'A', 'B', 'C', 'D', 'E', 'F' }; int len = strlen ( chs

js 不同进制之间相互转换

如果a进制与b进制都不等于10,则十进制作为桥梁进行转换 例如 10进制的数字11 转换为3进制为102 10进制的数字11 转换为4进制为23 现在进行3进制转4进制 1.3进制转10进制 2.10进制转4进制 ================= 在js里.我们可以借助 parseInt 跟 NumberObject.toString(radix) 方法来实现 parseInt()将数字转换为10进制数字, NumberObject.toString(radix)将10进制数字转换为目标进制数

16进制字符和图片之间相互转换

图片和字符转换一版用在socket进行通信之间.现在我就把我写的和测试整理出来和大家分享下 1:图片转换成16进制字符 1 FileStream fs = new FileStream(lbl_show.Text, FileMode.Open, FileAccess.Read); 2 BinaryReader br = new BinaryReader(fs); 3 StreamWriter sw = new StreamWriter(tb_position.Text); 4 int lengt