任意进制转换算法

简介:

任意进制转换算法

N年没有写博客,发个进制转换的玩下,支持负数;功能属于简化版的 Convert.ToInt32 ,特点是:

1、任意位,如:0,1(二进制),0...7(八进制),0...9,A...F(16进制),0...N(N进制),或者是:!@#$%^&*(8进制,字符符号),也可以是中文。

2、8 位最大长度。

3、C#源码。

最近写markdown格式习惯啦,cnblogs啥时候全改掉算了,别用这个htmleditor算了。

先说明下进制转换的基础知识,不会的可以了解下,会的就别看了,后面的也别看,纯粹属于浪费时间。

?
1
2
3
4
5
6
7
8
9
10
11
12
十六进制转十进制表
10 15 1
<--------------------------------------------------------------------
0 0 0 0 0 A F 1
<--------------------------------------------------------------------
16^7 16^6 16^5 16^4 16^3 16^2 16^1 16^0
268435456 16777216 1048576 65536 4096 256 16 1
<--------------------------------------------------------------------
(10*256) + (15*16) + (1*1)
=2560+240+1
=2801

  

复制代码
 十进制转十六进制表

          ^
19%16=3   | 0x3
19/16=1   | 0x1
          = 0x13H
复制代码

复制代码
 十六进制到二进制快速转换

 <-----------------------
 2^3   2^2  2^1  2^0
 8     4    2    1
 <-----------------------
 0xF821 = 1111 1000 0010 0001
 <-----------------------
 0xF = 15
     = 8 + 4 + 2 + 1
     = 1   1   1   1
 0x8 = 8
     = 8 + 0 + 0 + 0
     = 1   0   0   0
 0x2 = 2
     = 0 + 0 + 2 + 0
     = 0   0   1   0
 0x1 = 1
     = 0 + 0 + 0 + 1
     = 0   0   0   1
复制代码

复制代码
 二进制到十六进制快速转换
 <-----------------------
 2^3   2^2  2^1  2^0
 8     4    2    1
 <-----------------------
 1111 1000 0010 0001 = 0xF821
 <-----------------------
 1111    = 8 + 4 + 2 + 1
        = 15
        = 0xF
 1000    = 8 + 0 + 0 + 0
        = 8
        = 0x8
 0010    = 0 + 0 + 2 + 0
        = 2
        = 0x2
 0001    = 0 + 0 + 0 + 1
        = 1
        = 0x1
复制代码

复制代码
十进制快速转换十六进制
        103 = (6 * 16) + 7 = 0x67
        22  = (1 * 16) + 6 = 0x16
        54  = (3 * 16) + 6 = 0x36
        255 = (15* 16) + 15 = 0xff
        999 = (62 * 16) + 7 ~ 0x7
          62= (3 * 16) + 14 ~ 0xe
            = 3 ~ 0x3
            = 0x3e7
        9999= (624 * 16) + 15 ~ 0xF
         624= (39*16) + 0 ~ 0x0
          39= (2* 16) + 7 ~ 0x7
           2= 2 ~ 0x2
            = 0x270f
        1980= (123 * 16) + 12 ~ 0xc
         123= (7 * 16) + 11 ~ 0xb
           7= 7 ~ 0x7
            = 0x7bc
复制代码

计算过程摆完了,下面是测试代码(代码未经优化,纯属测试):

复制代码
    class MainClass
    {
        public static void Main (string[] args)
        {
            var nt = -3212;
            var ct = "";
            ct = ConvertToAny (nt, 0, "a,b,c");
            Console.WriteLine (ct);
            var rt = AnyToNumber (ct, "a,b,c");
            Console.WriteLine (rt);
            Console.WriteLine (Convert.ToString(nt,2));
            Console.ReadLine ();

            Console.WriteLine ("Test begin");
            for (int n = -1230; n < 1230; n++) {
                var a = n.ToString ("X");
                var b = ConvertToAny (n, 0, "0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F");
                if (a != b) {
                    Console.WriteLine ("[{2}]Error:a!=b: {0} {1}", a, b, n);
                } else if (n % 100 == 0) {
                    Console.WriteLine ("[{2}]Curr: a!=b: {0} {1}  OK", a, b, n);
                }
            }
            Console.WriteLine ("Test ok");

            Console.WriteLine ("Test begin");
            for (int n = -1230; n < 1230; n++) {
                var hex = n.ToString ("X");
                var a = Convert.ToInt32 (hex, 16);
                var b = AnyToNumber (hex, "0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F");
                if (a != b) {
                    Console.WriteLine ("[{2}]Error:a!=b: {0} {1}", a, b, hex);
                } else if (n % 100 == 0) {
                    Console.WriteLine ("[{2}]Curr: a!=b: {0} {1}  OK", a, b, hex);
                }
            }
            Console.WriteLine ("Test ok");
            Console.WriteLine (ConvertToAny (int.MaxValue, 0, "0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F"));
        }

        static bool isNegativeNumber(string any, string anyString ){
            var s = ConvertToAny (int.MaxValue, 0, anyString);
            if (s.Length != any.Length) {
                return false;
            } else {

                var ReverseTable = BuildReverseTable (anyString);

                if (ReverseTable [any [0].ToString ()] > ReverseTable [s [0].ToString ()]) {
                    return true;
                }
            }
            return false;
        }
        static int AnyToNumber (string any, string anyString = "0,1,2,3,4,5,6,7,8,9")
        {
            int sum = 0;
            var ConversionTable = BuildConversionTable (anyString);
            var ReverseTable = BuildReverseTable (anyString);
            var tableBit = ConversionTable.Count;

            bool negativeNumber = false;
            var conversionPadSize = 0;
            conversionPadSize = 128 / tableBit;
            if (tableBit < 10) {
                conversionPadSize /= 2;
            }
            //是否负数
            if( isNegativeNumber( any, anyString) ){
                negativeNumber = true;
                //反转
                var res = any;
                any = "";
                var moveBit = tableBit - 1;
                foreach (var c in res) {
                    any += NumberConversion (ConversionTable, moveBit - FindConversion (ReverseTable, c.ToString ()));
                }
            }
            var cur = any.Length - 1;
            for (var n = 0; n < any.Length; n++,cur--) {
                var c = any [n].ToString ();

                var bitSum = FindConversion (ReverseTable, c) * (int)Math.Pow (tableBit, cur);
                sum += bitSum;
            }
            if (negativeNumber) {
                //补位
                sum++;
                sum = 0 - sum;
            }
            return sum;
        }

        static string ConvertToAny (int number, int padSize = 8, string anyString = "0,1,2,3,4,5,6,7,8,9")
        {
            var conversionPadSize = padSize;

            var ConversionTable = BuildConversionTable (anyString);
            var ReverseTable = BuildReverseTable (anyString);
            var tableBit = ConversionTable.Count;

            long input = Math.Abs ((long)number);
            //补码
            if (number < 0) {
                input -= 1;

                conversionPadSize = 128 / tableBit;
                if (tableBit < 10) {
                    conversionPadSize /= 2;
                }
            }
            
            var result = "";
            while (true) {
                if (input >= tableBit) {
                    result = NumberConversion (ConversionTable, (int)(input % tableBit)) + result;
                    input = (int)(input / tableBit);
                } else {
                    result = NumberConversion (ConversionTable, (int)input) + result;
                    break;
                }
            }

            if (result.Length < conversionPadSize) {
                //补位
                result = StringPadLeft (result, conversionPadSize, ConversionTable [0]);
            } else {
//                //对齐
//                if (result.Length % 2 != 0) {
//                    result = ConversionTable[0] + result;
//                }
            }    

            if (number < 0) {
                //反转
                var res = result;
                result = "";
                var moveBit = tableBit - 1;
                foreach (var c in res) {
                    result += NumberConversion (ConversionTable, moveBit - FindConversion (ReverseTable, c.ToString ()));
                }
            }

            return result;
        }

        static string StringPadLeft (string src, int size, string c)
        {
            var nsize = size - src.Length;
            for (var n = 0; n < nsize; n++) {
                src = c + src;
            }
            return src;
        }

        static string NumberConversion (Dictionary<int,string> table, int n)
        {
            return table [n];
        }

        static int FindConversion (Dictionary<string,int> table, string c)
        {
            return table [c];
        }

        static Dictionary<string,int> BuildReverseTable (string tableString)
        {
            var table = tableString.Split (",".ToCharArray (), StringSplitOptions.RemoveEmptyEntries).ToList ();
            //补位操作,必须是2的倍数
            if (table.Count % 2 != 0) {
                table.Insert (0, "0");
            }
            var result = new Dictionary<string,int> ();
            for (var i = 0; i < table.Count; i++) {
                result.Add (table [i].ToString (), i);
            }
            return result;
        }

        static Dictionary<int,string> BuildConversionTable (string tableString)
        {
            var table = tableString.Split (",".ToCharArray (), StringSplitOptions.RemoveEmptyEntries).ToList ();
            //补位操作,必须是2的倍数
            if (table.Count % 2 != 0) {
                table.Insert (0, "0");
            }
            var result = new Dictionary<int,string> ();
            for (var i = 0; i < table.Count; i++) {
                result.Add (i, table [i].ToString ());
            }
            return result;
        }
    }
复制代码

有趣的测试:

转换结果

代码未经测试,自己可以完善




本文转自suifei博客园博客,原文链接:http://www.cnblogs.com/Chinasf/p/5547968.html,如需转载请自行联系原作者

相关文章
|
网络协议 Java
【工具】Mermaid + 大模型画流程图
最近看面试文章关于TCP三次握手和四次挥手的文章,时常会看到有类似的图去描述这样的过程。当然觉得这样的图还是蛮规范的,属于流程图的一种,是否有工具可以自动生成呢?但没有细想,昨天刷V2EX看到也有老哥发出了这样的问题。于是顺着评论区大佬的回答,我GET到了一个工具Mermaid 这里三次握手的图取自小林coding的文章
1330 0
|
XML Java 测试技术
通义灵码与githubcopilot的对比评测
本文评测了通义灵码,与github copilot在一些代码编写能力上面的能力比较。 虽然github copilot要强很多,但灵码目前的能力也不算很弱,并且在一些小类上会做的更好一些。 值得试试看,也是免费的
57900 10
|
消息中间件 Java 数据库
Spring事务监听机制---使用@TransactionalEventListener处理数据库事务提交成功后再执行操作(附:Spring4.2新特性讲解)【享学Spring】(上)
Spring事务监听机制---使用@TransactionalEventListener处理数据库事务提交成功后再执行操作(附:Spring4.2新特性讲解)【享学Spring】(上)
|
存储 JSON 前端开发
massCode 一款优秀的开源代码片段管理器
本文将介绍一款适合程序员使用的个人代码片段管理工具 massCode
2003 0
massCode 一款优秀的开源代码片段管理器
|
SQL 关系型数据库 MySQL
mysql加索引的时候到底会不会锁表.深入解析
默认大部分情况下 mysql的在线DDL可以让我们加索引的时候不锁表,但是也有一些限制的场景,跟本次问题相关的限制情况是在线DDL 操作完成之前,它必须等待在表上持有元数据锁(Metadata Lock)的事务提交或回滚。
12386 1
mysql加索引的时候到底会不会锁表.深入解析
|
缓存 Linux 网络安全
Docker 运行时的用户与组管理
docker 以进程为核心, 对系统资源进行隔离使用的管理工具. 隔离是通过 cgroups (control groups 进程控制组) 这个操作系统内核特性来实现的. 包括用户的参数限制、 帐户管理、 资源(CPU,内存,磁盘I/O,网络)使用的隔离等. docker 在运行时可以为容器内进程指定用户和组. 没有指定时默认是 root .但因为隔离的原因, 并不会因此丧失安全性. 传统上, 特定的应用都以特定的用户来运行, 在容器内进程指定运行程序的所属用户或组并不需要在 host 中事先创建.
3178 0
Docker 运行时的用户与组管理
|
算法 NoSQL Java
实战-全局唯一邀请码功能实现
实战-全局唯一邀请码功能实现
3559 2
|
程序员
程序员变量命名神器——CodeLf
作为程序猿,最头疼的是不是觉得变量名、方法名不会取名字,现在推荐款神器 -- CodeLf 。有了这个,以后代码的变量名就是 so easy 了,下面给大家讲解一下如何使用。
9712 0