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


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

  • 相关阅读:
    SHELL基础
    阿里
    Ansible基础
    js实现的跳转页面方法实现汇总
    绕过js-sdk,微信转发的时候在标题添加时间和地点。
    wechat-js-sdk
    js调用百度地图api实现定位
    微创网站工作总结:用错地方的资源
    项目进行时—整理
    js实现双击改变文本内容
  • 原文地址:https://www.cnblogs.com/4littleProgrammer/p/4739653.html
Copyright © 2020-2023  润新知