程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 自己實現各種進制相互轉換,進制相互轉換

自己實現各種進制相互轉換,進制相互轉換

編輯:C#入門知識

自己實現各種進制相互轉換,進制相互轉換


本文自己實現了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 也會更少,測試起來也更容易。所以,碰到一個問題或需求,切記不要馬上就敲代碼。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved