【类】深入理解进制及其转换,AutoHotkey进制转换(二进制 十进制 十六进制)函数,AutoHotkey v2.0+

一、进制

进制是一种数学表示方法,用于表示数字的方式。在计算机科学和电子工程中,进制是一个至关重要的概念,因为计算机使用的是二进制,而人们通常使用的是十进制。本文将介绍四种常见的进制:二进制、八进制、十进制和十六进制,并探讨它们之间的关系和转换。

四种常见进制

  1. 二进制(Binary)
    • 二进制是由 0 和 1 组成的进制系统。
    • 在计算机中,所有的数据都以二进制形式存储和处理。
    • 例如,二进制数 101 表示十进制数 5。
  2. 八进制(Octal)
    • 八进制是由 0 到 7 共八个数字组成的进制系统。
    • 在计算机领域,八进制常用于表示一组二进制数。
    • 例如,八进制数 17 表示十进制数 15。
  3. 十进制(Decimal)
    • 十进制是由 0 到 9 共十个数字组成的进制系统,是人们最常用的进制。
    • 在日常生活和数学运算中,我们通常使用十进制来表示数字。
    • 例如,十进制数 256 表示 256。
  4. 十六进制(Hexadecimal)
    • 十六进制是由 0 到 9 和 A 到 F 共十六个数字/字母组成的进制系统。
    • 在计算机领域,十六进制常用于表示二进制数,便于人们阅读和理解。
    • 例如,十六进制数 0xFF 表示十进制数 255。

二、进制转换原理

当我们谈论进制转换时,我们实际上是在改变数字的表示方式,而不是改变数字本身的值。进制转换的原理涉及到数字在不同进制下的表示方式。

  1. 十进制到其他进制的转换
    • 以十进制数为例,我们通过不断地除以目标进制的基数,然后取余数的方式来进行转换。具体地,我们从待转换的十进制数开始,不断除以目标进制的基数,每次取得的余数就是目标进制中的一位数字。将所有的余数按相反的顺序排列,就得到了目标进制表示的数值。
  2. 其他进制到十进制的转换
    • 以其他进制数为例,我们通过对每一位数字乘以对应进制的权值,然后相加的方式来进行转换。具体地,我们从待转换的数值的最低位(最右边)开始,每一位数字乘以相应的权值,然后将所有乘积相加,即可得到十进制表示的数值。
  3. 其他进制到其他进制的转换
    • 为了实现不同进制之间的转换,我们通常会利用十进制作为中间桥梁。我们先将原始数值转换为十进制,然后再将十进制数转换为目标进制。

举例说明:

从十进制到其他进制的转换

例如,将十进制数 100 转换为二进制。我们依次进行除法运算,每次取余数作为二进制的一位,直到商为 0。这个过程如下所示:

100 ÷ 2 = 50 ... 0
 50 ÷ 2 = 25 ... 0
 25 ÷ 2 = 12 ... 1
 12 ÷ 2 =  6 ... 0
  6 ÷ 2 =  3 ... 0
  3 ÷ 2 =  1 ... 1
  1 ÷ 2 =  0 ... 1

然后,我们从下往上读取余数,得到的二进制数为 1100100。

从其他进制到十进制的转换

例如,将二进制数 1101 转换为十进制。我们将每一位数字乘以对应的权值,然后相加,得到的结果如下:

1 * 2^3 + 1 * 2^2 + 0 * 2^1 + 1 * 2^0 = 8 + 4 + 0 + 1 = 13

因此,二进制数 1101 对应的十进制数为 13。

三、ConverterFunc 函数详解及注意事项

函数功能

ConverterFunc 函数用于进行进制转换,支持以下功能:

  • 任意进制之间的转换。

参数说明:

  • 参数格式:ConverterFunc 函数的参数格式为字符串,格式如下:”tobase关键字或输入值 [输入值] [目标进制]”。例如:”tobase 0xFF 8″、”256″、”(1010)”。
  • 二进制参数:转换类型为二进制时,输入值需要加上括号。例如,二进制数 (1010) 表示十进制数 10,函数调用应为:ConverterFunc(“(1010)”)。
  • 八进制参数:转换类型为八进制时,输入值需要以 “o” 开头。例如,八进制数 o17 表示十进制15,函数调用应为:ConverterFunc(“(o17)”)。
; 调用 ConverterFunc 函数并将参数 "256" 传递给它,然后弹出消息框显示结果
MsgBox ConverterFunc("256")       ; 将十进制转换为十六进制
MsgBox ConverterFunc("0xFF")      ; 将十六进制转换为十进制
MsgBox ConverterFunc("(1010)")  ; 将二进制转换为十进制
MsgBox ConverterFunc("o17")     ; 将八进制转换为十进制


MsgBox ConverterFunc("tobase 0xFF 8")      ; 将十六进制转换为八进制
MsgBox ConverterFunc("tobase 0xFF 2")      ; 将十六进制转换为二进制
MsgBox ConverterFunc("tobase 255 8")      ; 将十进制转换为八进制
MsgBox ConverterFunc("tobase 255 2")      ; 将十进制转换为二进制

四、函数和类

下面给出上面演示基于的类和函数。


; ConverterFunc 函数用于将数字转换为其他进制表示形式
ConverterFunc(str) 
{
    ; 调用 Converter 类中的 calculateExpression 方法来执行转换,并返回结果
    return fullResult := Converter.calculateExpression(str) ; (n < b ? "" : ToBase(n//b,b)) . ((d:=Mod(n,b)) < 10 ? d : Chr(d+55))
} 

; Converter 类定义了执行各种运算和转换的方法
class Converter
{
    ; calculateExpression 方法用于执行各种表达式计算和进制转换
    static calculateExpression(rawstr,callflag:=0)
    {
        ; 如果输入的是二进制字符串,先转换为十进制
        if (str := RTrim(LTrim(Trim(rawStr), "("), ")")) != Trim(rawStr) and not RegExReplace(str, "[10]", ""){
            return result := Utils.otherToTen(str, 2)
            ;fulltxt := rawStr . "=" . result
            ;return callflag ? result : fulltxt
        }
        ; 如果输入的是以 o 开头的八进制字符串,先转换为十进制
        if inStr(tr := trim(rawStr), "o") == 1 and not RegExReplace((str := subStr(tr, 2)), "\d+", "") {
            return result := Utils.otherToTen(str, 8)
            ;fulltxt := rawStr . "=" . result
            ;return callflag ? result : fulltxt
        }
        ; 如果输入的是以 0x 开头的十六进制字符串,直接转换为十进制
        if inStr(str1 := trim(rawStr), "0x") == 1 and not RegExReplace((str := subStr(str1, 3)), "[a-fA-F\d]+", "") {
            result := Format("{1:d}", str1)
            fulltxt := rawStr . "=" . result
            return result
        }
        ; 如果输入的是纯数字,则将其转换为十六进制
        if not RegExReplace((str := trim(rawStr)), "\d+", ""){
            result := Utils.tenToOther(str, 16)
            fulltxt := rawStr . "=0x" . result
            return "0x" . result
        }
        ; 如果输入的是 tobase 命令,则执行任意进制转换
        if instr(rawStr, "tobase ") == 1 and (str := Trim(LTrim(rawStr, "tobase "))){
            return result := this.tobaseExpression(str)
            ;fulltxt := rawStr . "=" . result
            ;return fulltxt
        }
    }
    
    ; tobaseExpression 方法用于执行进制转换
    static tobaseExpression(str)
    {
        ; 解析参数
        args := strSplit(RegExReplace(trim(str), "\s+", " "), " ")
        ; 如果参数为两个,执行指定进制的转换
        if (args.length == 2) {
            tmpMap := Map("2", "(", "8", "o", "16", "0x")
            return Utils.mapget(tmpMap, args[2]) . Utils.tenToOther(this.calculateExpression(args[1], 1), args[2]) . (args[2] == "2" ? ")" : "")
        }
        ; 如果参数为三个,执行任意进制之间的转换
        else if (args.length == 3) {
            return Utils.tenToOther(Utils.otherToTen(args[1], args[2]), args[3])
        }
    }
}

; Utils 类定义了一些静态方法用于辅助数学计算和进制转换
class Utils
{
    ; mapget 方法用于获取 Map 中的值
    static mapget(map1, key, ignoreCase:=0)
    {
        try {
            if ignoreCase {
                ; 忽略大小写查找
                for k, v in map1 {
                    if k = key
                        return v
                }
            }
            return map1.get(key)
        }
        catch as e {
            return ""
        }
    }
    
    ; otherToTen 方法用于将其他进制转换为十进制
    static otherToTen(n, b)
    {
        MI := strLen(n)  ; 计算字符串长度
        Loop  parse, n  ; 遍历字符串
            result .= A_Loopfield "*" b "^" MI-A_Index "+"  ; 构建表达式
        return this.polish_notation(rtrim(result, "+"))  ; 使用逆波兰表达式计算结果
    }
    
    ; tenToOther 方法用于将十进制转换为其他进制
    static tenToOther(n, b)
    {
        return (n < b ? "" : this.tenToOther(n // b, b)) . ((d := Mod(n, b)) < 10 ? d : Chr(d + 55))
    }
    
    ; polish_notation 方法用于计算逆波兰表达式
    static polish_notation(expression)
    {
        operator_list := Map("+", 0, "-", 0, "*", 0, "/", 0, "%", 0, "^", 0) ; 创建运算符列表
        operatorlevel_map := Map("(", 0, "+", 1, "-", 1, "*", 2, "/", 2, "%", 2, "^", 3, ")", 4) ; 创建运算符优先级映射
        operator_map := Map("+", "add", "-", "sub", "*", "multi", "/", "divi", "%", "mod2", "^", "pow") ; 创建运算符映射
        
        expression := strReplace(strReplace(RegExReplace(trim(expression), "\s+", ""), "**", "^"), "(-", "(0-") ; 格式化表达式
        
        ; 获取中缀表达式列表,例如:100+2 -> ["100", "+", "2"]
        middlefix_list := [], fix := ""
        Loop parse, expression {
            current_value := A_LoopField
            if (operatorlevel_map.has(current_value)) {
                tmp := "" != fix ? middlefix_list.push(fix) : ""
                middlefix_list.push(current_value)
                fix := ""
            } else 
                fix := fix . current_value
        }
        
        tmp2 := fix != "" ? middlefix_list.push(fix) : ""
        
        ; 处理开头为负数的情况
        if (middlefix_list[1] = "-") {
            middlefix_list.insertAt(1, "(")
            middlefix_list.insertAt(2, "0")
            middlefix_list.insertAt(5, ")")
        }
        
        ; 转换为后缀表达式(逆波兰表达式)
        operator_stack := [], suffix_list := [], number_stack := []
        for index, currentElmt in middlefix_list {
            if (operator_list.has(currentElmt)) {
                while (operator_stack.length > 0 && operatorlevel_map.get(operator_stack.get(operator_stack.Length)) >= operatorlevel_map.get(currentElmt))
                    suffix_list.push(operator_stack.pop())
                operator_stack.push(currentElmt)
            } else if (currentElmt = "(")
                operator_stack.push("(")
            else if (currentElmt = ")") {
                while (operator_stack.length > 0 && operatorlevel_map.get(operator_stack.get(operator_stack.length)) > operatorlevel_map.get("("))
                    suffix_list.push(operator_stack.pop())
                if (operator_stack.length > 0)
                    operator_stack.pop()
            } else
                suffix_list.push(currentElmt)
        }
        while (operator_stack.length > 0)
            suffix_list.push(operator_stack.pop())
        
        ; 计算表达式最终的值
        for key, opertor_or_number in suffix_list {
            if (operator_list.has(opertor_or_number)) {
                number2 := number_stack.pop(), number1 := number_stack.pop()
                tmpObj := {add: number1 + number2, sub: number1 - number2, multi: number1 * number2, pow: number1 ** number2}
                T1 := opertor_or_number = "/" ? (tmpObj.divi := number1 / number2) : ""  ; 处理除法
                T2 := opertor_or_number = "%" ? (tmpObj.mod2 := mod(number1, number2)) : ""  ; 处理取模
                number_stack.push(tmpObj.%operator_map.get(opertor_or_number)%)
            } else
                number_stack.push(opertor_or_number)
        }
        return number_stack.pop()
    }
}

给TA捐赠
共{{data.count}}人
人已捐赠
教程

Menu菜单你弄懂了吗?我终于弄懂了!

2021-9-3 13:54:56

教程

在行代码后自动插入一些空格,用注释符结束

2021-9-22 7:07:38

17 条回复 A文章作者 M管理员
  1. 孤独求败

    看看

  2. 岸上走

    前来学习

  3. 某亚瑟

    学习一下

  4. dbgba

    学习一下

  5. Tmz

    学习了

  6. AkiraMing

    感谢分享

  7. user15803

    学习一下

  8. 老王头

    学习

  9. 星雨朝霞

    学习一下进制转换

  10. 猪头来袭

    学习一下

  11. 平平淡淡

    学习一下进制转换

  12. Geron

    为啥评论后还是看不了呢?

  13. bbada

    全网就这里有

个人中心
购物车
优惠劵
有新私信 私信列表
搜索