# 各种进制

#include <iostream>
#include <string>

using namespace std;

// 十进制转其他进制
string decimalToBase(int n, int base) {
    string digits = "0123456789ABCDEF"; // 可根据需要扩展到更多进制
    string result = "";
    while (n > 0) {
        int remainder = n % base;
        result = digits[remainder] + result;
        n = n / base;
    }
    return result;
}

// 其他进制转十进制
int baseToDecimal(string num, int base) {
    string digits = "0123456789ABCDEF"; // 可根据需要扩展到更多进制
    int result = 0;
    int power = 0;
    for (int i = num.length() - 1; i >= 0; --i) {
        int value = digits.find(num[i]);
        result += value * pow(base, power);
        power++;
    }
    return result;
}

// 其他进制之间的转换
string baseConversion(string num, int fromBase, int toBase) {
    int decimal = baseToDecimal(num, fromBase);
    string result = decimalToBase(decimal, toBase);
    return result;
}

int main() {
    // 十进制转二进制
    cout << decimalToBase(10, 2) << endl; // 输出: 1010

    // 二进制转十进制
    cout << baseToDecimal("1010", 2) << endl; // 输出: 10

    // 二进制转十六进制
    cout << baseConversion("1010", 2, 16) << endl; // 输出: A

    // 十六进制转八进制
    cout << baseConversion("A", 16, 8) << endl; // 输出: 12

    return 0;
}

# 二进制的深入探究

在将小数转换为二进制时,需要使用一种特殊的表示方法,称为浮点数表示法或二进制浮点表示法。这是因为大多数小数无法在有限位的二进制中准确表示。

常见的浮点数表示方法是 IEEE 754 标准,它定义了单精度浮点数(32 位)和双精度浮点数(64 位)的格式。下面我们以单精度浮点数为例,介绍如何将小数转换为二进制。

  1. 将小数的整数部分转换为二进制:将小数的整数部分不断除以 2,并记录每次的余数,直到商为 0 为止。然后将这些余数倒序排列,得到整数部分的二进制。

  2. 将小数的小数部分转换为二进制:将小数的小数部分不断乘以 2,并取出整数部分作为二进制的一位。然后将剩余的小数部分再次乘以 2,继续取整数部分,直到小数部分为 0 或达到所需的精度。

  3. 组合整数部分和小数部分的二进制:将整数部分的二进制与小数部分的二进制进行组合,用一个特定的标志位来表示小数点的位置。

需要注意的是,由于二进制是有限位的,对于某些小数,转换为二进制后可能无法精确表示。这可能会导致舍入误差和精度损失。因此,在进行浮点数计算时,需要注意处理这些舍入误差。

以下是一个示例,将小数 0.625 转换为单精度浮点数的二进制表示:

  1. 整数部分:0 的二进制表示为 0。
  2. 小数部分:0.625 乘以 2 的结果是 1.25,取整数部分 1,剩余小数部分为 0.25。继续乘以 2,得到整数部分 0,剩余小数部分为 0.5。再次乘以 2,得到整数部分 1,剩余小数部分为 0。小数部分转换为二进制为 "101"。
  3. 组合整数部分和小数部分:整数部分为 0,小数部分为 "101",小数点位置为 3(从小数部分的左边开始计数)。所以 0.625 的二进制表示为 0.101。

请注意,实际上,IEEE 754 标准对于浮点数的表示和转换有更复杂的规则,涉及到指数位、符号位等。这里只给出了简化的示例来说明基本的过程。

#include <iostream>
#include <string>
std::string decimalToBinary(double decimal) {
    if (decimal < 0 || decimal >= 1) {
        return "Invalid decimal";
    }
    std::string binary = "0.";
    while (decimal > 0) {
        decimal *= 2;
        int bit = static_cast<int>(decimal);
        binary += std::to_string(bit);
        decimal -= bit;
    }
    return binary;
}
int main() {
    double decimal = 0.625;
    std::cout << decimalToBinary(decimal) << std::endl;  // 输出:0.101
    return 0;
}

对于负数的二进制表示,通常有两种方法:原码和补码。

  1. 原码表示法

在原码表示法中,一个负数的二进制表示的最高位为符号位,0 表示正数,1 表示负数。其他位按照正数的二进制表示方法来表示绝对值大小。例如,-3 的原码为 10000011。

原码表示法最大的问题就是加法运算不方便,需要考虑符号位以及进位等情况。因此,补码表示法被广泛使用。

  1. 补码表示法

在补码表示法中,一个负数的二进制表示的计算方式和正数不同,需要先求出该数的绝对值二进制表示,然后取其反码,再将结果加 1。其中,反码表示方式为将二进制表示中每个位取反(0 变为 1,1 变为 0),符号位不变。

例如,-3 的补码为 11111101。具体过程如下:

-3 的绝对值为 3,其二进制表示为 00000011;

对该二进制表示取反得到 11111100,这就是 - 3 的反码;

将反码加 1,即得到补码 11111101。

注意,在补码表示法中,最高位的符号位不参与运算,只用来表示正负。加减乘除运算都是直接在补码上进行,无需特别考虑符号位的影响。

对于负数的二进制表示,无论是原码还是补码,其最高位均为 1,因此,在计算机中表示负数时,需要占用更多的位数。例如,在 8 位二进制中,可以表示 - 128 到 127 之间的整数,其中 0 到 127 为正数,128 到 255 为负数。

# 逻辑命题与位运算

逻辑命题是一个陈述句,可以被判定为真或假的陈述。它通常用于逻辑推理和数学证明中。

以下是一些常见的逻辑命题形式:

  1. "今天是星期天":这是一个具体的命题,要么为真(如果今天确实是星期天),要么为假(如果今天不是星期天)。

  2. "2 加 2 等于 4":这是一个数学命题,为真。

  3. "地球是平的":这是一个错误的命题,为假。

  4. "如果下雨,那么地面湿润":这是一个条件命题,如果下雨,则地面湿润,否则为假。

  5. "所有的猫都有尾巴":这是一个普遍命题,如果所有的猫都有尾巴,则为真,否则为假。

逻辑命题可以通过观察、推理或实验来确定其真值。在逻辑推理中,根据逻辑规则和前提,我们可以推导出新的命题。逻辑命题在数学、哲学、计算机科学等领域中都发挥着重要的作用。

位运算是一种操作二进制数的运算,它直接对二进制数的位进行操作,而不是像普通四则运算那样对数值进行操作。位运算符号包括按位与(&)、按位或(|)、按位异或(^)、按位取反(~)、左移(<<)和右移(>>)。

下面是每种位运算符号的具体含义和用法:

  1. 按位与(&):将两个二进制数的每一位进行运算,只有当两个对应位都为 1 时,结果才为 1,否则为 0。例如,0b1011 & 0b1100 = 0b1000。

  2. 按位或(|):将两个二进制数的每一位进行运算,只要两个对应位中有一个为 1,结果就为 1,否则为 0。例如,0b1011 | 0b1100 = 0b1111。

  3. 按位异或(^):将两个二进制数的每一位进行运算,如果两个对应位相同,则结果为 0,否则为 1。例如,0b1011 ^ 0b1100 = 0b0111。

  4. 按位取反():将一个二进制数的每一位取反,即 0 变为 1,1 变为 0。例如,0b1011 = 0b0100。

  5. 左移(<<):将一个二进制数向左移动指定的位数。例如,0b1011 << 2 = 0b110100。

  6. 右移(>>):将一个二进制数向右移动指定的位数。例如,0b1011 >> 2 = 0b10。

位运算通常用于对某些位进行掩码、清除或设置。例如,要将一个二进制数的第 3 位清零,可以使用按位与运算符和掩码:num & 0b11110111。要将一个二进制数的第 4 位设置为 1,可以使用按位或运算符和掩码:num | 0b00001000。此外,位运算还可以用于实现一些高效的算法和数据结构,例如布隆过滤器和哈希表。