博客

  • #C++ Day11 October 21 2025

    //6 – 2 – 1 while

    #include <iostream>

    #include <string>

    using namespace std;

    int main() {

    /*int count = 0;

    while (count < 1000) {

    cout << “I love you!” << endl;

    count += 1;

    }*/

    /*while (1) {

    cout << “I love you!” << endl;

    count += 1;

    //dead repeat

    }*/

    //string a;

    //while (cin >> a) {

    // cout << a+ ” I love you!” << endl;

    //}

    int a,b;

    while (cin >> a >> b) {

    cout << a+ b << endl;

    }

    return 0;

    }

    //6 – 2 – 2 do-while

    #include <iostream>

    using namespace std;

    int main() {

    /*

    do {

    } while (condition);

    */

    //if the condition is true, keep on execution

    /*int a = 0;

    do {

    cout << a << endl;

    a += 1;

    } while (a < 3);

    a = 0;

    while (a < 3) {

    cout << a << endl;

    a += 1;

    }*/

    int a = 3;

    do {

    cout << a << ” haha” << endl;

    a += 1;

    } while (a < 3); 

    //do-while will first execute the do case at least once,then continue to  judge the while’s conditon 

    cout << “—–” << endl;

    a = 3;

    //The while will judge the condition at first, if the condition is false, the sentence won’t be executed

    while (a < 3) {

    cout << a << ” gg” << endl;

    a += 1;

    }

    return 0;

    }

    AI:

    等差数列求和公式详解

    要理解等差数列的求和公式,首先需要明确等差数列的基本定义,再通过推导过程掌握公式的本质,最终学会根据已知条件选择合适的公式计算。

    一、等差数列的基本概念

    在等差数列中,有几个核心量需要先明确,后续公式均围绕这些量展开:

    • 首项:数列的第一个数,记为 ( a_1 )(例如数列 ( 2,5,8,11\cdots ) 中,( a_1=2 ));
    • 公差:相邻两项的差值(后项减前项),记为 ( d )(上述数列中,( d=5-2=3 ),且所有相邻项差值恒定);
    • 项数:数列中元素的个数,记为 ( n )(例如求“前5项和”时,( n=5 ));
    • 末项:数列的第 ( n ) 项,记为 ( a_n )(可由首项和公差推导:( a_n = a_1 + (n-1)d ),上述数列第5项为 ( a_5=2+(5-1)\times3=14 ));
    • 前( n )项和:数列前 ( n ) 个元素的总和,记为 ( S_n )(本文核心求算目标)。

    二、等差数列的两个核心求和公式

    等差数列求和公式有两种形式,分别适用于“已知末项”和“未知末项”的场景,本质是相通的(可相互推导)。

    公式1:已知首项、末项和项数(最直观的形式)

    公式表达式:

    [ S_n = \frac{n(a_1 + a_n)}{2} ]

    推导过程(倒序相加法,高斯求和的本质):

    以“求 ( 1+2+3+\cdots+100 ) 的和”为例,高斯的思路可推广到所有等差数列:

    1. 写出前 ( n ) 项和的正序:( S_n = a_1 + (a_1+d) + (a_1+2d) + \cdots + a_n );
    2. 写出前 ( n ) 项和的倒序:( S_n = a_n + (a_n-d) + (a_n-2d) + \cdots + a_1 );
    3. 将正序和倒序对应项相加,每一组的和均为 ( a_1 + a_n )(例如正序第1项+倒序第1项:( a_1+a_n );正序第2项+倒序第2项:( (a_1+d)+(a_n-d)=a_1+a_n ),以此类推);
    4. 总共有 ( n ) 组这样的和,因此:( 2S_n = n(a_1 + a_n) ),两边除以2即得公式1。

    适用场景:

    已知 ( a_1 )(首项)、( a_n )(末项)、( n )(项数),直接代入计算。

    示例:求等差数列 ( 3,7,11,15 ) 的前4项和。

    已知 ( a_1=3 ),( a_4=15 ),( n=4 ),代入公式:

    ( S_4 = \frac{4\times(3+15)}{2} = 4\times9 = 36 )(验证:( 3+7+11+15=36 ),结果正确)。

    公式2:已知首项、公差和项数(无需先求末项)

    公式表达式:

    [ S_n = na_1 + \frac{n(n-1)d}{2} \quad \text{或} \quad S_n = \frac{n\left[2a_1 + (n-1)d\right]}{2} ]

    推导过程(由公式1转化而来):

    因为等差数列的末项 ( a_n = a_1 + (n-1)d ),将其代入公式1:

    [ S_n = \frac{n\left[a_1 + a_1 + (n-1)d\right]}{2} = \frac{n\left[2a_1 + (n-1)d\right]}{2} ]

    展开后即可得到 ( S_n = na_1 + \frac{n(n-1)d}{2} )(两种形式等价,前者更便于分步计算)。

    适用场景:

    已知 ( a_1 )(首项)、( d )(公差)、( n )(项数),无需先求末项,直接代入计算。

    示例:求等差数列 ( 2,5,8,11\cdots ) 的前6项和。

    已知 ( a_1=2 ),( d=3 ),( n=6 ),代入公式:

    ( S_6 = 6\times2 + \frac{6\times(6-1)\times3}{2} = 12 + \frac{6\times5\times3}{2} = 12 + 45 = 57 )(验证:( 2+5+8+11+14+17=57 ),结果正确)。

    三、公式选择与注意事项

    1. 公式选择原则
      1. 若已知“末项 ( a_n )”,优先用公式1(计算更简洁);
      2. 若未知“末项 ( a_n )”,但已知“公差 ( d )”,用公式2(避免额外计算末项)。
    2. 关键易错点
      1. 项数 ( n ) 的确定:例如“求数列 ( 4,7,10\cdots,31 ) 的项数”,需用 ( a_n = a_1 + (n-1)d ) 反推:( 31 = 4 + (n-1)\times3 ),解得 ( n=10 )(注意:不是 ( (31-4)\div3=9 ),需加1);
      2. 公差 ( d ) 的符号:若数列为递减数列(如 ( 10,7,4,1\cdots )),公差 ( d=-3 ),代入公式时需保留负号,避免符号错误。

    四、总结

    等差数列求和的核心是“利用数列的对称性(倒序相加)”或“用首项、公差表示所有项”,两个公式的关系可总结为:

    [ \boxed{S_n = \frac{n(a_1 + a_n)}{2} \xleftrightarrow{\text{代入 } a_n = a_1 + (n-1)d} S_n = \frac{n\left[2a_1 + (n-1)d\right]}{2}} ]

    记忆时无需死记硬背,理解推导逻辑后,可根据已知条件灵活选择公式。

    //6 – 2 – 3 for

    #include <iostream>

    using namespace std;

    int main() {

    //a is initial condition

    //b is the stop step condition

    //c is the sentence that will be executed when each time we finished the {} sentence’s execution

    /*for (a;b ; c)

    {

    }*/

    /*int sum = 0;

    for (int i =1; i <= 5; ++i)

    {

    sum += i;

    }

    cout << sum << endl;*/

    /*int n;

    //method 1

    while (cin >> n) {

    int sum = 0;

    for (int i = 1; i <= n; ++i) {

    sum += i;

    }

    cout << sum << endl;

    }*/

    /*int n;

    //method 2

    while (cin >> n) {

    int sum = 0;

    int i = 1;

    for (; i <= n; ++i) {

    sum += i;

    }

    cout << sum << endl;

    }*/

    /*

    int n;

    //method 3

    while (cin >> n) {

    int sum;

    int i;

    for (sum = 0, i = 1; i <= n; ++i) {

    sum += i;

    }

    cout << sum << endl;

    }

    */

    /*

    int n;

    //4.dead repeat

    while (cin >> n) {

    int sum;

    int i;

    for (sum = 0, i = 1;; ++i) {

    sum += i;

    }

    cout << sum << endl;

    }

    */

    int n;

    //4.dead repeat

    while (cin >> n) {

    int sum;

    int i;

    for (sum = 0, i = 1;i<=n; ) {

    sum += i;

    ++i;

    }

    cout << sum << endl;

    }

    //while repeat doesn’t have the initial step

    return 0;

    }

    //6-3-1 break

    #include <iostream>

    using namespace std;

    int main() {

    //1. the break in while;

    int cnt = 0;

    while (1) {

    cnt++;

    cout << “current number is ” << cnt << endl;

    if (cnt > 20) {

    break;

    //break is jump out this repeat

    }

    }

    cout << “——-” << endl;

    //2. the break in for;

    cnt = 20;

    for (int i = 1; ;++i) {

    cout << “current number is ” << i << endl;

    if (i > cnt) {

    break;

    //break is jump out this repeat

    }

    //if this if sentence wrote in the for condition 2’s place, the code will be more complicative

    }

    cout << “——-” << endl;

    //3. the break in switch case;

    int  a = 1;

    switch (a) {

    case 1:

    cout << “Vito” << endl;

    break; //if we aren’t all this break,the least included default will be outputed until met the break again

    case 2:

    cout << “Algorithm” << endl;

    default:

    cout << “Algorithm2” << endl;

    }

    return 0;

    }

    //6 – 3 – 2 continue

    #include <iostream>

    using namespace std;

    int main() {

    /*

    for (int i = 0; i < 10; ++i)

    {

    if (i < 3) {

    continue;

    }

    cout << i << endl;

    }

    */

    /*

    for (int i = 0; i < 10; )

    {

    if (i < 3) {

    continue;

    //after the continue, the program will judege the for’s condition 2

    }

    cout << i << endl;

    ++i;

    //if we put the ++i on this place, this repetition will be the dead repetition, we must pay more attention when continue existed in the for sentence

    }

    */

    int a;

    while (cin >> a){

    if (a == 0) {

    continue;

    //continue is end up this time’s repetition

    }

    cout << a << endl;

    }

    return 0;

    }

  • #C++ Day10 October 16 2025

    Daily Sign in

    October 20 2025

    //6-1-1 if

    #include <iostream>

    using namespace std;

    int main() {

    /*if (express rule)

    rule1

    */

    int a = 43545435341;

    if (a % 2 == 1){

    cout << “a is an odd number” << endl;

    }

    int b;

    cin >> b;

    //==1 can be ignore, because if can recognize the 0(False) or the other numbers(True)

    if (b % 2 ) {

    cout << “b is an odd number” << endl;

    }

    if (b % 2) 

    cout << “b is an odd number” << endl;// if there is no {} symbol to select, there won’t execute the next line in this if express

    b = 3;// this one won’t be executed like the upper lineWW

    cout << “b is ” << b << endl;

    return 0;

    }

    //6-1-2 if else

    #include <iostream>

    using namespace std;

    int main() {

    /*

    if (exp1){

    rule1

    }

    else{

    rule2

    }

    */

    int x;

    cin >> x;

    string y = “add brick”;

    if (x & 1) {

    cout << “x is an odd number” << endl;

    y = y + ” JAVA”;

    }

    else {

    cout << “x is an even number” << endl;

    }

    cout << y << endl;

    return 0;

    }

    AI:

    这个问题抓得很准,位与判断奇数的核心就藏在二进制的最末位里!

    位与(&)能判断奇数,本质是利用了二进制数的末尾特征位与运算的规则。当一个数和数字 1 进行位与时,结果直接反映了这个数的奇偶性。

    1. 关键前提:二进制的 “奇偶密码”

    所有整数的二进制表示中,最后一位(最低位)直接决定了它是奇数还是偶数:

    • 奇数:二进制末尾一定是 1。比如 3(11)、5(101)、7(111)。
    • 偶数:二进制末尾一定是 0。比如 2(10)、4(100)、6(110)。

    这是因为二进制中,末尾位的权重是 \(2^0=1\),其他位的权重都是 2 的倍数(如 \(2^1=2\)、\(2^2=4\))。一个数的奇偶,本质就是看它是否包含 “1” 这个最小的奇数分量。

    2. 核心规则:位与(&)的运算逻辑

    位与运算的规则很简单:两个二进制位必须同时为 1,结果才是 1;否则结果为 0

    当我们用任意整数 n 和数字 1 进行位与时(即 n & 1),实际只关注 n 的二进制最后一位:

    • 若 n 是奇数(末尾为 1):1 & 1 = 1,最终结果为 1。
    • 若 n 是偶数(末尾为 0):0 & 1 = 0,最终结果为 0。

    3. 实例验证:一看就懂

    用具体数字举例,能更直观理解:

    十进制数(n二进制表示n & 1 的运算运算结果判断结论
    3(奇数)1111 & 01 = 011奇数
    4(偶数)100100 & 001 = 0000偶数
    7(奇数)111111 & 001 = 0011奇数
    8(偶数)10001000 & 0001 = 00000偶数

    要不要我帮你整理一份位运算判断奇偶的代码示例表?包含 Python、Java 等常见语言的具体写法,你可以直接参考使用。

    //6 – 1 – 3 else if

    #include <iostream>

    using namespace std;

    int main() {

    int  a;

    cin >> a;

    if (a==0) {

    cout << “Vito Algorithm” << endl;

    }

    //if (如果)

    //else if(否则如果)

    else if (a==1) {

    cout << “Vito1 Algorithm Legendary” << endl;

    }

    else if (a == 2) {

    cout << “Vito Algorithm Killer” << endl;

    }

    else if (a == 3) {

    cout << “Vito Algorithm Learner” << endl;

    }

    else{

    //the last else can be ignored

    cout << “Vito Another Algorithm” << endl;

    }

    return 0;

    }

    //6 – 1 – 4 conditional/ternary operator

    #include <iostream>

    using namespace std;

    int main() {

    int a = 3, b = 4;

    float c = 1.6;

    int x = -1;

    if (a > b) {

    x = a;

    }

    else {

    x = b;

    }

    //exp1? exp2:exp3;

    //if expression1 is true, then execute expression2, otherwise execute expresssion3

    x = (a > b ? a : b);

    x = (a > b) ? ( (a>c) ? a : c) : b; //ternary operator supports nest

    // the value type in ternary is depend on the values’ type

    cout << ((a > b) ? ((a > c) ? a : c) : c)<<endl;//1.6,output a float number

    cout << ((a < b) ? ((a > c) ? a : c) : c) << endl;//3,output an int number

    //If you think you can’t solve the priority problems, then you better add some quote symbols.

    return 0;

    }

    //6 – 1 – 5 switch case

    #include <iostream>

    using namespace std;

    int main() {

    int a = 0;

    cin >> a;

    /*

    if (a == 0) {

    cout << “Zero” << endl;

    }

    else if(a == 1) {

    cout << “One” << endl;

    }

    else if (a == 2) {

    cout << “Two” << endl;

    }

    else if (a == 3) {

    cout << “Three” << endl;

    }

    else{

    cout << “Beyond three or below zero” << endl;

    }

    */

    switch (a) {

    case 0:

    cout << “Zero” << endl;

    break; // If we didn’t add this break, then would execute next line until met the break, which is execute from up to down

    case 1:

    cout << “One” << endl;

    case 2:

    cout << “Two” << endl;

    break;

    case 3:

    cout << “Three” << endl;

    break;

    /*case 7.7:

    cout << “Three” << endl;

    break;*/

    case ‘4’:

    cout << “Four” << endl;

    break;

    //the switch expression must use int number or the ” char  to set the case, but the char ” will be recognized as the ascii codes

    case ‘9’-‘2’:

    //offset (偏移量),’9′ is 57 , ‘2’ is 50 , they are minus each other will be 7

    cout << “‘9’-‘2’ is 7” << endl;

    break;

    default:

    //If there weren’t meet the condition, if would jumped to the default case, which is equal to the if-else grammar’s else condition

    cout << “Beyond three or below zero” << endl;

    }

    return 0;

    }

  • #C++ Day9 October 15 2025

    //5 – 6 – 5 left shift operator

    #include <iostream>

    using namespace std;

    /*

    x << y    =  x * 2^y

    binary operator (二元运算符)

    */

    int main() {

    //1.positive number’s left shift

    int x = 0b11; //3

    x = (x << 1); // 6;0b110;left shift one bit, it will be multiple 2

    cout << x << endl;

    cout << “—————–” << endl;

    cout << (x<<4) << endl;//x*2^4

    cout << “—————–” << endl;

    //2.negative number’s left shift

    int y = -1;

    y = (y << 1);//-1*2^1

    cout << y << endl;

    cout << “—————–” << endl;

    //3.left shift negative’s bits

    int z = 64;

    z = (z << (-1));//it don’t allow the left shift’s right value is a negative number;despite some decoder can output it

    cout << z << endl;

    cout << “—————–” << endl;

    //4.left shift overflow

    int a = 64;

    a = (a << 10);//it don’t allow the left shift’s right value is a negative number;despite some decoder can output it

    cout << a << endl;

    //64=0b1000000

    //31 = 0b1…0000000000000000000000000000000000000

    //the int only can store 4bytes,so that the 1 will be cut out(截断)

    //left shift = *2 ;unstoppable *2 must be overflow

    cout << “—————–” << endl;

    return 0;

    }

    //5 – 6 – 6 right shift operator

    #include <iostream>

    using namespace std;

    /*

    x>>y right shift = x/2^y

    */

    int main() {

    //1.postive number’s right shift

    int a = 0b111; //7

    a = (a >> 1); // 7/2^1=3;cut out the rightest 1,and the remaining 0b11 will be 3

    cout << a << endl;

    cout << “——–” << endl;

    //2.negative number’s right shift

    int  b = -1;

    cout << (-1 >> 1) << endl;//-1

    //11111111 11111111 11111111 11111111   this is -1-> right shift 1 bit–>//01111111 11111111 11111111 1111111  –> 11111111 11111111 11111111 1111111(finally it will be 1 on the symbol bit)

    cout << “——–” << endl;

    //3.remove the lower k’s bits

    int c = 0b10000101; 

    cout << (c >> 7) << endl;//removed 0000101

    cout << “——–” << endl;

    //4.retrive the lower k’s bits’ value

    int d = 0b101010101;

    //   1

    cout << ((d >> 4) & 1) << endl;//if the fourth bit is 1,after the bitwising,there will be output 1

    return 0;

    }

    AI:

    要理解 “11111111 11111111 11111111 11111111” 为何代表 – 1,核心在于计算机中整数的二进制表示规则—— 尤其是 “补码(Two’s Complement)” 编码方式。计算机为了统一处理正数和负数的加减运算,规定了带符号整数的存储格式,32 位(4 个字节,每个字节 8 位)带符号整数的表示逻辑如下:

    1. 先明确前提:这是 32 位 “带符号整数” 的二进制

    计算机中的整数分为两类:

    • 无符号整数(unsigned):仅表示非负数,所有二进制位都用于存储数值(范围:0 ~ 2³²-1);
    • 带符号整数(signed):需区分正负,规定最高位(第 31 位,从 0 开始计数)为符号位
      • 符号位 = 0 → 正数;
      • 符号位 = 1 → 负数。

    你给出的 “11111111 11111111 11111111 11111111” 是 32 位二进制,且最高位为 1,因此它是一个带符号负数,需用 “补码” 规则解析其实际值。

    2. 关键规则:负数用 “补码” 存储

    为了避免 “正 0” 和 “负 0” 的重复(如 8 位二进制中,00000000 和 10000000 都表示 0),同时让 “正数 + 负数” 的运算等同于普通二进制加法(无需额外处理符号),计算机规定:

    正数的原码、反码、补码完全相同;负数的补码 = 其 “绝对值的原码” 按位取反(反码) + 1

    反过来,若已知一个负数的补码,要计算其实际值,需执行逆操作

    负数的绝对值 = (补码 按位取反) + 1,再加上负号。

    3. 一步步计算:32 位全 1 补码对应的值

    对 “11111111 11111111 11111111 11111111” 执行逆操作:

    • 补码按位取反:将所有 1 变为 0,所有 0 变为 1。
      32 位全 1 的补码取反后,结果是 00000000 00000000 00000000 00000000(32 位全 0)。
    • 取反后 + 1:00000000…00000000 + 1 = 00000000 00000000 00000000 00000001(即十进制的 1)。
    • 加上负号:由于原补码的符号位为 1(表示负数),因此最终值为 -1

    4. 延伸验证:8 位带符号整数的例子

    若将范围缩小到 8 位(1 字节),“11111111” 同样是 – 1,逻辑完全一致:

    • 8 位全 1 的补码 → 符号位 = 1(负数);
    • 按位取反:00000000 → +1 后 = 00000001(十进制 1);
    • 最终值:-1。

    而 8 位带符号整数的范围是 -128 ~ +127(正是补码规则的结果),32 位带符号整数的范围则是 -2³¹ ~ +2³¹-1,其中 “11111111 11111111 11111111 11111111” 恰好是这个范围中的 “-1”。

    总结

    “11111111 11111111 11111111 11111111” 代表 – 1,本质是计算机用32 位带符号整数的补码规则存储负数的结果:

    符号位为 1(表示负数),其补码对应的绝对值为 1,因此最终值为 – 1。

  • #C++ Day8 October 14 2025

    //5 – 6 – 3 XOR Exclusive OR operator

    #include <iostream>

    using namespace std;

    /*

    ^ XOR :XOR from high to low,if two values are unequal, there will be 1

    */

    int main() {

    //1.the XOR’s definition

    int a = 0b1010;

    int b = 0b0110;

    //  ^ = 0b1100; //Dec = 12

    cout << (a ^ b) << endl;

    cout << “———-” << endl;

    //2.Reverse the flag bit

    int c = 0b1000101;

    // 0b0001000;

    cout << c  << endl;

    cout << (c ^ 0b1000) << endl; // the first xor

    cout << ((c ^ 0b1000) ^ 0b1000) << endl;//xor again,xor is adaptive to the exchange and combine rules

    //two equal values,then xor will be full of the 0

    cout << “———-” << endl;

    //3.exchange the values

    int d = 17;

    int e = 19;

    d = d ^ e;

    e = d ^ e; // = d’ ^ e = d ^ e ^ e = d ^ 0 = d

    d = d ^ e; // = d’ ^ d = d ^ e ^ d = d ^ d ^ e =0 ^ e = e, xor is adapt to the exchange rule

    cout << d << ‘ ‘ << e << endl;

    //3.1 any values xor with 0, it’s the same value ifself;

    //3.2 two same values xor, the output will be 0;

    //3.3 xor is adaptive to the exchange and the combine rule;

    //exclusive OR(XOR):not promote bit’s  binary add rule(不带进位的二进制加法)

    cout << “———-” << endl;

    //4.occur the odd’s number(出现奇数次的数)

    int f = 3;//0b011

    int g = 4;//0b100

    int res = f ^ g ^ f; //=f^f^g=0^g=g

    cout << res << endl;

    //even’s number will finally become 0, and the odds will be left finally

    cout << “———-” << endl;

    //5.encrypt

    int x = 1314;

    cout << “520” << x << endl;

    int y = (x ^ 3135); // 3135 is the key

    cout << “520” << y << endl; //5202333

    cout << “520” << (y ^ 3135) << endl; //decrypt

    return 0;

    }

    AI:

    好问题👍

    这个其实是理解 XOR(异或)运算 的核心所在。我们慢慢来,不急着看公式。先一步步想清楚概念。

    先回忆一下普通的 二进制加法:

    A B A+B(带进位)

    0 0 0

    0 1 1

    1 0 1

    1 1 10(进位1,结果0)

    看到最后一行了吗?

    只有当 A 和 B 都是 1 时,才会产生 进位。

    现在我们看 XOR 的真值表:

    A B A⊕B

    0 0 0

    0 1 1

    1 0 1

    1 1 0

    是不是发现——

    XOR 跟普通加法几乎一模一样,只是当 1+1 时,它不产生进位,而是直接输出 0。

    也就是说:

    XOR 就像是在做「不考虑进位」的二进制加法。

    我们换个角度想:

    在二进制加法里,其实结果有两个部分:

    1. 和(Sum):就是不带进位的部分 → A ⊕ B

    2. 进位(Carry):是产生进位的部分 → A & B

    所以:

    A + B = (A ⊕ B) + ((A & B) << 1)

    这就是计算机做加法的原理(位运算实现加法)。

    我想确认你理解到这里:

    你能解释一下「为什么当 A=1 且 B=1 时 XOR 的结果是 0 吗」?

    (提示:想想这时“1+1”的结果在二进制下是什么样的)

    AI2:

    对!你说对了 👏

    不过我们可以再把这句话拆开一点,让逻辑更清晰。

    A=1、B=1 时,普通加法得到 10(也就是结果位 0,进位 1)。

    而 XOR 只保留“结果位”,不管进位,所以它只取 0。

    换句话说:

    • 普通加法 = 结果位 + 进位

    • XOR = 只要结果位,不要进位

    所以我们说它是 “不带进位的二进制加法”

    来,我们检验一下你的理解:

    我给你两个二进制数:

    A = 1011  

    B = 1101

    你能试着算出 A ⊕ B 的结果吗?

    (一步一步来,不用急——我们只做 XOR,不带进位的)

    AI3:

    太棒了 🎯 完全正确!

    我们来一起验证一下思路:

       1011

    ⊕  1101

    =  0110

    逐位解释:

    A B A⊕B

    1 1 0

    0 1 1

    1 0 1

    1 1 0

    ✅ 结果:0110

    小结一下:

    • XOR(异或)相当于“不带进位的二进制加法”;

    • 如果要做完整的加法,就要加上 进位 = A & B 的那一部分。

    想让我带你一起推一推,怎么用 “XOR + AND + 移位” 来在 C 语言里实现一个不用 + 的加法器吗?

    AI4:

    很好~那我们一起来“拆解”加法器的思路吧。

    我们先从逻辑讲起,不直接写代码。

    🧩 第一步:回忆一下我们刚才说的公式

    普通二进制加法可以写成:

    Sum = A ⊕ B          // 不带进位的部分

    Carry = (A & B) << 1  // 进位,往左移一位

    但这个 Carry 可能又会跟 Sum 相加,还会继续产生新的进位。

    所以我们要 重复这个过程,直到进位变成 0。

    💡 第二步:我们可以用循环实现这个过程

    每一轮做的事:

    1. sum = a ⊕ b

    2. carry = (a & b) << 1

    3. 把 a = sum, b = carry

    4. 继续直到 carry == 0

    🔧 第三步:用 C 语言写出来

    int add(int a, int b) {

        while (b != 0) {

            int sum = a ^ b;       // 不带进位的和

            int carry = (a & b) << 1; // 计算进位

            a = sum;               // 更新a

            b = carry;             // 更新b

        }

        return a;

    }

    这个算法完全没用 + 或 -,却能实现加法。

    现在我想考考你 😏

    假如我们输入 add(5, 3),

    你能试着写出每一轮循环里 a、b、sum、carry 的变化吗?(我们可以先看前两轮)

    AI5:

    没关系~这个地方第一次接触确实有点绕,我们慢慢拆开。

    我们先换个思路:别看代码,先把**“加法的过程”**想象成两步循环发生的事。

    🧠 想象一下你要算 5 + 3

    先写成二进制:

    5 = 0101  

    3 = 0011

    第一步:XOR,不带进位加法

    我们先做 “不带进位”的加法(XOR):

    0101

    ⊕ 0011

    = 0110   ← 这就是 6

    但因为有些地方 “1+1” 了(会产生进位),我们还得算出进位

    第二步:AND,然后左移一位

    计算哪些位置产生进位:

    0101

    & 0011

    = 0001

    进位要往左移动一位(因为二进制加法中进位加到下一列):

    0001 << 1 = 0010

    这代表进位是 2。

    第三步:再加一次

    现在我们要把

    不带进位的结果 0110 (6)

    再加上进位 0010 (2)

    所以我们又回到第一步——再做一次 XOR + AND。

    看到这个循环了吗?

    每次做:

    1. 不带进位加法(XOR)

    2. 算出新的进位(AND << 1)

    3. 如果进位不为 0,就再来一轮。

    最后进位变成 0,结果就是最终的和。

    这样解释有点清楚了吗?

    要不要我帮你把上面的例子(5 + 3)一步步继续算完,让你看到循环怎么结束的?

    AI6:

    很好,我们就把刚才那个例子(5 + 3)一步一步完整推到底 💪

    🧩 起始值:

    a = 0101 (5)

    b = 0011 (3)

    🌀 第 1 轮循环

    1️⃣ 不带进位加法(XOR)

    0101

    ⊕ 0011

    = 0110   → sum = 6

    2️⃣ 计算进位(AND,然后左移)

    0101

    & 0011

    = 0001

    0001 << 1 = 0010   → carry = 2

    更新 a、b:

    a = 0110 (6)

    b = 0010 (2)

    🌀 第 2 轮循环

    1️⃣ XOR

    0110

    ⊕ 0010

    = 0100   → sum = 4

    2️⃣ AND + 左移

    0110

    & 0010 = 0010

    0010 << 1 = 0100   → carry = 4

    更新 a、b:

    a = 0100 (4)

    b = 0100 (4)

    🌀 第 3 轮循环

    1️⃣ XOR

    0100

    ⊕ 0100

    = 0000   → sum = 0

    2️⃣ AND + 左移

    0100

    & 0100 = 0100

    0100 << 1 = 1000   → carry = 8

    更新 a、b:

    a = 0000

    b = 1000

    🌀 第 4 轮循环

    1️⃣ XOR

    0000

    ⊕ 1000

    = 1000   → sum = 8

    2️⃣ AND + 左移

    0000

    & 1000 = 0000

    0000 << 1 = 0000   → carry = 0

    这时 b = 0,循环结束 ✅

    🎯 最终结果

    a = 1000(二进制)

    = 8(十进制)

    所以 add(5, 3) 的结果就是 8

    你能看到:

    • 每一轮 “不带进位加法” 用 XOR;

    • 每一轮 “进位” 用 AND 然后左移;

    • 不断重复,直到进位没了。

    要不要我帮你画一张小图,把这个「XOR + AND + 循环」的逻辑画成流程图?那样会更容易记。

    AI7:

    你的结论非常准确!**异或(XOR)运算确实是找到“数组中出现奇数次数字”的高效方法**,尤其适用于“只有1个或2个数字出现奇数次,其余数字均出现偶数次”的场景。其核心优势在于**时间复杂度O(n)、空间复杂度O(1)**(无需额外存储大量数据),远优于哈希表等需要额外空间的方法。

    要理解为什么XOR能做到这一点,首先需要掌握XOR运算的4条核心性质,这是整个逻辑的基础:

    ### 一、XOR运算的核心性质

    异或运算用符号“^”表示,运算规则是“**相同为0,不同为1**”(二进制层面),但从实用角度,更关键的是其推导出来的4条规律:

    1. **交换律**:`a ^ b = b ^ a`(顺序不影响结果)  

    2. **结合律**:`(a ^ b) ^ c = a ^ (b ^ c)`(分组不影响结果)  

    3. **自身异或为0**:`a ^ a = 0`(一个数和自己异或,结果为0)  

    4. **与0异或为自身**:`a ^ 0 = a`(一个数和0异或,结果还是它本身)  

    ### 二、场景1:只有1个数字出现奇数次,其余均为偶数次

    这是最基础的场景,也是XOR应用的核心。

    #### 原理推导:

    假设数组为`[a, b, c, a, b]`,其中`c`出现1次(奇数次),`a`和`b`各出现2次(偶数次)。  

    根据交换律和结合律,我们可以将“相同数字”优先分组异或:  

    `(a ^ a) ^ (b ^ b) ^ c`  

    根据“自身异或为0”,`a^a=0`,`b^b=0`,代入后得到:  

    `0 ^ 0 ^ c`  

    再根据“与0异或为自身”,`0^0=0`,最终结果为:  

    `0 ^ c = c`  

    可见,**所有出现偶数次的数字会通过异或“抵消”为0,最终剩下的就是出现奇数次的数字**。

    #### 实例演示:

    数组`[2, 3, 2, 4, 4, 3, 3]`,其中`3`出现3次(奇数次),其余数字各出现2次(偶数次)。  

    计算过程:  

    `2 ^ 3 ^ 2 ^ 4 ^ 4 ^ 3 ^ 3`  

    = `(2^2) ^ (3^3^3) ^ (4^4)`  

    = `0 ^ (0 ^ 3) ^ 0`  

    = `0 ^ 3 ^ 0`  

    = `3`  

    最终结果恰好是出现奇数次的`3`。

    ### 三、场景2:有2个数字出现奇数次,其余均为偶数次

    如果数组中有2个数字(设为`x`和`y`)出现奇数次,其余均为偶数次,XOR同样能解决,但需要多一步“分组拆分”。

    #### 原理推导:

    1. **第一步:得到x^y**  

       对整个数组异或,所有出现偶数次的数字会抵消为0,最终结果为:`0 ^ x ^ y = x ^ y`(记为`res = x ^ y`)。  

       由于`x ≠ y`(若x=y则出现次数为偶数,矛盾),`res`的二进制中**至少有1位是1**(这是关键:说明x和y在这一位上的二进制值不同)。

    2. **第二步:找到“区分位”,拆分数组**  

       找到`res`中任意一个为1的二进制位(比如最低位的1,记为`mask`)。  

       用`mask`对数组中所有数字进行“与运算”:  

       – 数字与`mask`的结果为1:放入组A(这类数字在“区分位”上为1)  

       – 数字与`mask`的结果为0:放入组B(这类数字在“区分位”上为0)  

       由于`mask`是`x^y`的为1的位,`x`和`y`会被分到不同的组(一个在A,一个在B),且**每组内只有1个数字出现奇数次**(其余均为偶数次)。

    3. **第三步:分别求x和y**  

       对组A所有数字异或,得到其中出现奇数次的数字(比如`x`);  

       对组B所有数字异或,得到另一个出现奇数次的数字(比如`y`)。

    #### 实例演示:

    数组`[1, 2, 3, 2, 3, 4, 4, 5]`,其中`1`和`5`各出现1次(奇数次),其余数字各出现2次(偶数次)。  

    1. 全数组异或:`1^2^3^2^3^4^4^5 = 1^5 = 4`(二进制`100`,即`res=4`)。  

    2. 找区分位:`res=4`的最低为1的位是第3位(二进制`100`),`mask=4`。  

    3. 分组:  

       – 组A(数字&4=1):`4`(4&4=4≠1?重新算:数组中数字是1(001)、2(010)、3(011)、4(100)、5(101)。mask=4(100),则:  

         – 1&4=0 → 组B  

         – 2&4=0 → 组B  

         – 3&4=0 → 组B  

         – 4&4=4 → 组A  

         – 5&4=4 → 组A  

       最终组A:`[4,4,5]`(5出现1次奇数次),组B:`[1,2,3,2,3]`(1出现1次奇数次)。  

    4. 分组异或:  

       – 组A异或:`4^4^5=5`  

       – 组B异或:`1^2^3^2^3=1`  

       得到两个出现奇数次的数字`1`和`5`。

    ### 四、注意事项

    XOR的这个用法有一个严格前提:**除了目标数字(1个或2个),其余所有数字必须出现偶数次**。如果有3个及以上数字出现奇数次,单纯用XOR无法直接找到所有目标(需要结合更复杂的逻辑,如哈希表统计次数)。

    综上,XOR利用其独特的运算性质,实现了“零额外空间找奇数次数字”的高效解法,是算法面试中非常经典的考点。

    AI8-1:

    很好 👍 那我们就从「为什么要有补码」讲起。

    在计算机里,加法和减法最好都能用“加法器”来完成,因为电路实现加法比减法简单。

    但问题是:

    如果我们用“原码”表示负数,比如:

    十进制 原码(二进制 8 位)

    +5 0000 0101

    -5 1000 0101

    你会发现:

    (+5) + (-5) = 0000 0101 + 1000 0101 = 1000 1010 → 这并不是 0!

    所以原码不能直接用于运算。

    于是就有了一个聪明的办法——补码(Two’s Complement)

    它的思路是:

    让“负数”变成一种特殊的正数形式,这样加法电路就能处理它。

    计算规则(以 8 位为例):

    1️⃣ 正数的补码 = 原码(不变)

    2️⃣ 负数的补码 = 先取反(把 1→0,0→1),再 +1

    例如:

    -5 的原码是 1000 0101

    → 取反:0111 1010

    → 加 1:0111 1011

    所以 -5 的补码是 1111 1011(注意最高位 1 表示负号)。

    当你用补码运算时:

    (+5) + (-5)

    = 0000 0101 + 1111 1011 = 1 0000 0000

    去掉溢出的最高位 → 0000 0000 ✅(结果正确!)

    我想让你试一下:

    👉 请你帮我算算,在 8 位系统下,-3 的补码是什么?

    (记得:先取反,再加 1)

    AI8-2:

    非常好 👏,你算得完全正确!

    我们来验证一下你的过程:

    • 原码(-3):1000 0011

    • 取反:0111 1100

    • 加 1:0111 1101

    → 所以补码是 1111 1101 ✅

    现在你已经理解了补码的生成方式。

    我们再往下一步走一点:

    你觉得用补码来表示负数,有什么好处呢?

    (提示:它跟加法、减法、电路设计的关系很大~)

    AI8-3:

    完全正确!👏👏

    你已经抓到补码最关键的两个优点了:

    1️⃣ 简化电路设计

    因为加法和减法都可以用同一个“加法器”完成。

    举个例子:

    想算 5 – 3,其实就是 5 + (-3)。

    如果 -3 用补码表示,就能直接丢进加法器里计算。

    2️⃣ 避免算错数(特别是符号位的问题)

    在原码或反码下,符号位要单独处理,容易出错;

    但补码让符号位“融入”了数值部分,整体运算更自然。

    来个小练习巩固一下?

    👉 如果是 8 位系统,1111 0110 这个补码代表的是十进制多少?

    (提示:你可以先判断它是正数还是负数,再反推出原码。)

    //5 – 6 – 4 reverse relied on each bit(bitwise NOT)

    #include <iostream>

    using namespace std;

    /*

    ~  reverse relied on each bit’s symbol(bitwise NOT)

    this is an unary operator(单目运算符)

    */

    int main() {

    //1.the unary operator’s (reverse relied on each bit’s symbol) definition

    int a = 0b00000000000000000000000000000001;

    int b = 0b11111111111111111111111111111110; //four 8 bits number

    cout << (~a) << endl; //-2

    cout << b << endl; //-2

    cout << “—————” << endl; 

    //2.Two’s Complement(补码)

    //if 0b00000000000000000000000000000000 =  0

    //and if 0b11111111111111111111111111111111 = -1

    //then minus 1  0b11111111111111111111111111111110 = -2

    int c = 0b0;

    cout << (~c) << endl; // 32 bits’ 1 will output -1

    cout << “—————” << endl;

    //3.get the reverse number

    int d = 18;

    cout << (~d + 1) << endl;//-18

    //原码、反码、补码、移码

    //1’s ~ (bitwise NOT) is -2

    //0’s ~ (bitwise NOT) is -1

    return 0;

    }

    AI8-3:

    在计算机中,0b0(二进制0)按位取反后结果为-1,这是由**按位取反的运算规则**和**补码表示法**共同决定的,核心原因在于计算机用补码表示有符号整数。

    ### 具体分析步骤:

    #### 1. 明确“0b0”的二进制完整形式

    在计算机中,整数通常以固定位数(如32位、64位)的二进制存储。例如,32位系统中,`0b0`(十进制0)的二进制是**32个0**:  

    `00000000 00000000 00000000 00000000`  

    #### 2. 按位取反(~)的运算规则

    按位取反会将二进制的每一位都翻转(0变1,1变0)。因此,32位的0取反后,所有0都会变成1,结果是**32个1**:  

    `11111111 11111111 11111111 11111111`  

    #### 3. 补码中“全1”表示-1

    计算机中,有符号整数用**补码**表示,规则是:  

    – 正数的补码 = 原码(符号位为0,数值位为本身);  

    – 负数的补码 = 反码 + 1(反码是原码除符号位外取反)。  

    而“全1”的二进制(如32位的`11111111…1111`)恰好是-1的补码:  

    – 推导:假设求-1的32位补码  

      – 1的原码:`00000000…0001`  

      – 1的反码(除符号位外取反):`11111111…1110`(符号位为1,表示负数)  

      – 反码加1得补码:`11111111…1110 + 1 = 11111111…1111`  

    #### 4. 验证逻辑合理性

    从运算逻辑上看,-1的补码“全1”满足补码的核心特性:**负数加其绝对值等于0**。  

    例如:`-1 + 1 = 0`  

    – -1的补码:`11111111…1111`  

    – 1的补码:`00000000…0001`  

    – 相加结果:`11111111…1111 + 00000000…0001 = 100000000…0000`(溢出后截断为32位,结果为`00000000…0000`,即0),完全符合逻辑。  

    ### 结论

    0b0按位取反后得到“全1”的二进制,而在补码表示法中,“全1”恰好是-1的编码,因此结果为-1。这是计算机为了统一加减法运算(将减法转化为加法)而设计的补码规则导致的必然结果。

    AI9-1:

    为什么 这样 //3.get the reverse number

    int d = 18;

    cout << (~d + 1) << endl;//-18

    这段代码的输出结果为`-18`,核心原因是:**`~d + 1` 是计算机中求一个整数相反数(负数)的标准操作**,这是由补码的运算规则决定的。

    ### 具体分析步骤:

    #### 1. 明确 `d = 18` 的二进制补码

    在C++中,`int` 通常为32位有符号整数,用补码表示。  

    18的二进制原码(正数的补码与原码相同)为:  

    `00000000 00000000 00000000 00010010`  

    #### 2. 按位取反 `~d` 的结果

    `~` 是按位取反运算符,将二进制每一位翻转(0变1,1变0)。  

    对18的补码取反后得到:  

    `11111111 11111111 11111111 11101101`  

    #### 3. 加1操作 `~d + 1` 的结果

    取反后加1,得到:  

    `11111111 11111111 11111111 11101101 + 1 = 11111111 11111111 11111111 11101110`  

    #### 4. 该结果是 `-18` 的补码

    在补码规则中,负数的补码定义为“其绝对值的反码 + 1”。  

    – 18的绝对值是18,其原码为 `00000000…00010010`  

    – 反码为 `11111111…11101101`(除符号位外取反)  

    – 反码加1后正是 `11111111…11101110`,即 `-18` 的补码。  

    ### 结论

    `~d + 1` 本质是**通过补码运算求 `d` 的相反数**。对于任意整数 `d`,`~d + 1` 的结果恒等于 `-d`,因此当 `d = 18` 时,输出自然为 `-18`。这是计算机中利用补码统一加减法运算的典型应用。

    AI9-2:

    哦,你这里用的这一行代码,其实就是在用 补码的原理 来求负数。我们慢慢拆开来看:

    int d = 18;

    cout << (~d + 1) << endl;  // 输出 -18

    1️⃣ ~d 是什么?

    • ~ 是 按位取反(bitwise NOT)

    • 18 的二进制(32 位 int 为例):

    00000000 00000000 00000000 00010010

    • 取反后:

    11111111 11111111 11111111 11101101

    这就是 18 的反码

    2️⃣ +1 是为什么?

    • 在补码表示中,负数 = 取反 +1

    • 所以:

    ~18 + 1

    = 11111111 11111111 11111111 11101101 + 1

    = 11111111 11111111 11111111 11101110

    • 这就是 -18 的补码,所以输出就是 -18。

    🔑 核心理解

    • ~d + 1 就是 求 d 的补码负数

    • 换句话说,这种方式可以把一个正数变成负数

    如果你愿意,我可以画一张 正数 → 取反 → +1 → 负数补码 的流程图,让你一眼就看懂为什么会是 -18。

    AI10:

    好呀,我们把这些概念理一理,它们都是计算机表示有符号数的方法,但用法和原理不同。我们用 8 位为例子来讲。

    1️⃣原码(Sign-Magnitude

    规则:最高位是符号位,0 表示正,1 表示负,其余位表示数值大小。

    例子

    • +5 → 0000 0101

    • -5 → 1000 0101

    问题:加减法电路麻烦,需要特殊处理符号位。

    2️⃣反码(Ones’ Complement

    规则

    • 正数:与原码相同

    • 负数:原码符号位不变,其余位取反

    例子

    • +5 → 0000 0101

    • -5 → 1111 1010

    特点:减法可以用加法器做,但有“0 的两种表示”(0000 0000 和 1111 1111)。

    3️⃣补码(Two’s Complement

    规则

    • 正数:原码不变

    • 负数:取反 +1

    例子

    • +5 → 0000 0101

    • -5 → 1111 1011

    特点

    • 加减法都可以直接用加法器

    • 只有一种 0 表示

    • 最高位仍表示符号(1 负,0 正)

    4️⃣移码(Biased / Excess-K

    规则:把原码加上一个偏移值(bias),通常 bias = 2^(n-1),使所有数都是正数

    用途:浮点数指数部分常用移码

    例子(8 位,bias = 128):

    • 真值 0 → 1000 0000

    • 真值 -5 → 1000 0000 – 5 = 0111 1011

    • 真值 +5 → 1000 0000 + 5 = 1000 0101

    如果你愿意,我可以画一张图表把原码、反码、补码、移码对比起来,一眼就能看懂它们的关系。

    你想要我画吗?

  • #C++ Day7 October 13 2025

    //5 – 6 – 1 bitwise AND operator

    #include <iostream>

    using namespace std;

    /*

    & if there has one 0, there must be 0

    && if there has one false, there must be false

    */

    int main() {

    //1.bitwise AND operator’s definition

    int a = 0b1010; //10

    //0b is mean that binary

    int b = 0b0110; //6

    //   0010      

    cout << (a & b) << endl;//2

    cout << “————-” << endl;

    //2.Parity odd number and even number

    cout << (5 % 2) << endl; // we can know this 5 is also an odd number by moding 2;

    //this kind of manipulator’s priority is high and the efficiency is high too

    cout << (5 & 1) << endl;//we can know this 5 is also an odd number by bitwising AND  1

    //this kind of manipulator’s priority is lower than the mod manipulate,but the  efficiency is the same as bitwise AND manipulator

    //0b101

    //0b001

    //On the binary, if the last bit have the odd number,the whole value must be the odd number

    cout << “————-” << endl;

    //3.retrive the last 5 bits of a number

    int c = 0b1010010101001;

    cout << (c & 0b11111) << endl; // the last 5 bits set binary’s 11111

    cout << “————-” << endl;

    //4.let the last 5 bits into the zero

    int d = 0b11111111111111111111111111100000;

    cout << (c & d) << endl; //  the output must be 0b1010010100000, which is the last 5 bits of c turned into 0,the dec is 5280

    cout << “————-” << endl;

    //5.clean the last continuous 1 on the latter bits

    int e = 0b101010111111;

    //e+1 = 0b101011000000

    // &  = 0b101010000000

    //0b101010000000

    cout << (e & (e + 1)) << endl;

    cout << “————-” << endl;

    //6.to judge the power(幂) of 2 

    int f = 0b100000000;

    //f-1=  0b011111111

    // & =  0b000000000 = 0

    //((f>0)&&( f & (f-1))==0;if equal to 0,the f value must be the power of 2

    cout << (f-1) << endl;

    cout << (f & (f – 1)) << endl;

    return 0;

    }

    //5 – 6 – 2 bitwise OR operator

    #include <iostream>

    using namespace std;

    /*

     | if there has one 1, there must be 1

     || if there has one true, there must true

    */

    int main() {

    //1.the definition of bitwise OR

    int a = 0b1010; //10

    int b = 0b0110; //6

    //  | = 0b1110; // 14

    cout << (a | b) << endl;

    cout << “———” << endl;

    //2.set the flag bit(标记位)

    int c = 0b100111; // 39

    // 0b101111  // 47

    cout << (c | (0b1000)) << endl;

    cout << “———” << endl;

    //3.unset the flag bit

    //0b100111 ->0b100110

    int d = 0b000001;

    // use or operator,and let the last bit become 1 ,then minus the last 1, the operator is adapt to all the number included the last bit has 1 or not has 1

    cout << ((c | d) – d) << endl;

    cout << “———” << endl;

    //4.let last continuous bits’ 0 turned into  1

    int e = 0b1010010000;

    //e-1 = 0b1010001111;

    // & -> 0b1010011111;

    int f = 0b1010011111;

    //  0b1010010000 ->  0b1010011111;

    cout << f << endl;

    cout << (e | (e – 1)) << endl;

    return 0;

    }

  • #C++ Day6 October 12 2025

    //5-3 compare symbol

    #include <iostream>

    using namespace std;

    //== equal

    //!= unequal

    //>  bigger than

    //<  smaller than

    //>= bigger than or equal to

    //<= smaller than or equal to

    int main() {

    int a = 6;

    int b = 9;

    cout << (a == b) << endl; //because << ‘s level is much higher than ==, so we must add () to solve the problem

    cout << (a != b) << endl;

    cout << (a > b) << endl;

    cout << (a < b) << endl;

    cout << (a >= b) << endl;

    cout << (a <= b) << endl;

    return 0;

    }

    //5 – 4 logic symbol

    #include <iostream>

    using namespace std;

    //&& and

    //|| or

    //!  not

    //the priority : ||<&&<!

    // one number symbol’s class is the highest

    //if you don’t know the class, you can add some ()  into it 

    int main() {

    //two values has 2^2 kinds of outcomes

    //1. && and calculate: if have false, there must false

    cout << (0 && 0) << endl;

    cout << (0 && 1) << endl;

    cout << (1 && 0) << endl;

    cout << (1 && 1) << endl; //when all the maniplate numbers are true, the outcome must true, otherwise the outcome is false

    cout << (0 && 0) << endl;

    cout << (0 && 2) << endl;

    cout << (2 && 0) << endl;

    cout << (2 && 2) << endl;//when all the maniplate numbers are true, the outcome must true, otherwise the outcome is false

    // 2 or more the same as 1, because of the algorithm only care about the number is 1 or not 1

    cout << “———” << endl;

    //2.|| or calculate:where there have one true, there must true

    cout << (0 || 0) << endl;

    cout << (0 || 2) << endl;

    cout << (2 || 0) << endl;

    cout << (2 || 2) << endl;// this wave line inform me there is only need one true before the ||  

    cout << “———” << endl;

    //3. ! not calculate:not true is false, not false is true

    cout <<  !0 << endl;

    cout << !2 << endl;

    cout << “———” << endl;

    int a = !((5 > 4) && (7 – 8) && (0 – 1));

    cout << a << endl;

    int b = !(1 || 1 && 0); // the && and symbol’s class is higher than the || or maniplate symbol

    cout << b << endl;

    return 0;

    }

    //5 – 5, comma symbol

    #include <iostream>

    using namespace std;

    int main() {

    int a = 1;//must has an origin value

    //a = 5 – 6, 8 + 9, 100 / 7;//the , comma ‘s priority is really low, lower than the = ,so we must add () into it

    a = (5 – 6, 8 + 9, 100 / 7);//the , comma ‘s priority is really low, lower than the = ,so we must add () into it

    //-1 ,17 ,14

    //the comma symbol will output the last value

    cout << a << endl;

    //example 1:

    int x = 4;

    int y = 5;

    cout << x << ” ” << y << endl;

    int temp = x;

    x = y;

    y = temp;

    cout << x << ” ” << y << endl;

    //we can use it in a loop,which can easily change the value 

    temp = x, x = y, y = temp;

    cout << x << ” ” << y << endl;

    return 0;

    }

  • #C++ Day5 October 11 2025


    //5-1-1 math symbols


    #include <iostream>


    using namespace std;



    int main() {


    int a = 1;


    int b = 3;


    cout << a+b << endl;


    cout << a – b << endl;


    cout << a * b << endl;


    cout << a / b << endl; //if int divide int, there will be int too


    cout << a*1.0 / b << endl;//if int multiple float before divide, there will be float



    a = 10000000;


    b = 100000;


    cout << a * b << endl; //output will out the range of int


    cout << (long long)a * b << endl; //we can translate it forcely



    a = -1;


    b = 2;


    cout << a / b << endl;//just cut of the dot number



    a = +1;


    b = -a;


    int c = -(-a);


    cout << a <<‘ ‘ << b <<‘ ‘ << c << endl;//postive & negative



    char A = ‘A’;


    A = A + 1;


    A = A + 24;



    cout << A << endl;



    return 0;


    }




    //5-1-2 mod % symbol


    #include <iostream>


    using namespace std;



    int main(){


    int a = 100;


    int b = 9;


    cout << a % b << endl; //1



    a = 100;


    b = -9;


    cout << a % b << endl; //1



    a = -100;


    b = 9;


    cout << a % b << endl;//the mod symbol %;-100 % 9 is  9*-11 (near 0 direction) not -12 in C/C++ launguage


    //-1





    a = -100;


    b = -9;


    cout << a % b << endl; //-100 -(-9)*11=-1


    //-1



    //1、the symbol of mod is the same as the be devided number


    //first we should take the negative symbol from the  be devided number 


    //second we use it as 100 = -9 * (-11) + 1 


    //third the left +1 is the lease number and add the negative symbol – to the 1


    //fourth the final answer is  -1


    return 0;


    }




    //5 – 1-3 ++ & –symbol


    #include <iostream>


    using namespace std;



    int main() {


    int a = 6; 


    a++; //a=a+1


    cout << a << endl;


    ++a; //a=a+1


    cout << a << endl;


    //the same in the two ways



    int j = 8;


    int x = a++; //first give the value to x, then add 1 to a


    int y = ++j; //first add 1 to the value , then give the value to y (this type is more effective)


    cout << x << endl; 


    cout << y << endl;



    int z = (a++) + (++a);//9+11=20 we must not to write this type code ,because it will make a big problem


    cout << z << endl;



    a–; //a=a-1


    cout << a << endl;


    –a;//a=a-1


    cout << a << endl; 


    }



    //5 – 2 valued symbols


    #include <iostream>


    using namespace std;



    int main() {


    int x = 9;


    int y = 6;


    x = y; // let y to x


    cout << x << endl;



    x += y; //x=x+y   the length is 10 bytes to 7 bytes


    cout << x << endl;



    x -= y; //x=x-y


    cout << x << endl;



    x *= y; //x=x*y


    cout << x << endl;



    x /= y; //x=x/y


    cout << x << endl;



    x %= y; //x=x%y


    cout << x << endl;


    return 0;


    }






  • #C++ Day4 Sep 14 2025

    #include <iostream>

    using namespace std;

    int main() {

    char a = ‘y’; //use the single quotes can be recognized the char type

    char b = ‘z’;

    //char a =”y”;//using double quotes can be recognized as a lot of string

    cout << a << endl;

    cout << int(a) << endl; //cause 1 byte can be 1*2^8=256 ,so that can be include ascii symbol

    //cout << b – a << endl;

    b = 121;

    cout << b << endl;

    cout << sizeof(a) << endl;

    cout << sizeof(char) << endl;

    return 0;

    }

    Day4 October 10 2025

    //4-5 translate words

    #include <iostream>

    using namespace std;

    int main() {

    char a = ‘\a’;

    char n = ‘\n’; //ascii = 7 , which is \a and would make a beep sound

    cout << int(a) << endl;

    cout << “Vito \”Al\”\\gorith\088m Union\tV\0ito” << n; // \n as a key words change the line;\t is tab ;\\can output a \;\0 will cut out;

    //\” can output the ” normally

    return 0;

    }

    /*

    \0xx is a octal(8 position rule)

    \088 would not recognized a real function

    \077 is a ? symbol

    */

    //4-6 string

    #include <iostream>

    #include <string>

    using namespace std;

    int main() {

    char a[] = “维克托算法联盟”; //the end of the string will be a ‘\0’, which made it as the string for the system recognizing 

    //the GBK UTF-8 can change the encode ways 

    //this is the C style string

    cout << sizeof(a) << endl;

    cout << a << endl;

    string b = “夜深人静看算法”;//this is C++ style string 

    cout << b +”vito” << endl; // import the string class can add another string easily 

    return 0;

    }

    //4-7 type bool

    #include <iostream>

    using namespace std;

    // bool is true or flase

    int main() {

    bool flag1 = false;

    bool flag2 = true;

    cout << flag1 << endl << flag2 << endl;

    cout << sizeof(bool) << endl;

    flag1 = !flag1;

    cout << flag1 << endl << flag2 << endl;

    cout << sizeof(flag1) << endl;//bool’s size is 1

    int flag3 = 0;

    cout << sizeof(flag3) << endl; // int=byte, which size is 4

    return 0;

    }

    //4-8 input

    #include <iostream>

    #include <string>

    //i=input

    //o = output

    using namespace std;

    int main() {

    //1.int’s input

    int a = 5;

    cin >> a; // the right used to input into some variables

    cout << “a turned to :” << a << endl;

    //2.float’s input

    double b = 5;

    cin >> b; // the right used to input into some variables

    cout << “b turned to :” << b << endl;

    //3.char’s input

    char c = 5;

    cin >> c; // the right used to input into some variables

    cout << “c turned to :” << c << endl;

    //4.string’s input

    string d = “”;

    cin >> d; // the right used to input into some variables

    cout << “d turned to :” << d << endl;

    //5.bool’s input

    bool e = false;

    cin >> e; // the right used to input into some variables

    cout << “e turned to :” << e << endl;

    return 0;

    //all the input must be legal

    }

  • #C++ Day3 Sep 11 2025

    #include <iostream>

    using namespace std;

    int main()

    // short 2字节     00       2 ^16   [-2 ^ 15 ~2 ^ 15 – 1]  [-32768~32767]

    // int 4字节       0000     2 ^ 16  [-2 ^ 31 ~2 ^ 31 – 1] [-2147483648~2147483647]

    // long 4字节 8字节 0000     2 ^ 16  [-2 ^ 31 ~2 ^ 31 – 1]

    // long long 8字节 00000000  2 ^ 16 [-2 ^ 63 ~2 ^ 63 – 1]

    //[l,r]

    // range:r-l+1

    //make it close to the range can save the space ,so watch out the range

    {

        short a = 32768; // will be get out of the range,and turn to the loop’s start -32768

        int b = 2147483648;

        long c = 1;

        long long d = 1;

        cout << “a=” << a << endl;

        a = 32769;

        cout << “a2=” << a << endl; // show out -32767

        cout << “b=” << b << endl;

        cout << “c=” << c << endl;

        cout << “d=” << d << endl;

        return 0;

    }

    //new reserver symbol sizeof()

    #include <iostream>

    using namespace std;

    int main()

    {

        short a = 1;

        int b = 1;

        long c = 1;

        long long d = 1;

        cout << sizeof(short) << endl;

        cout << sizeof(int) << endl;

        cout << sizeof(long) << endl;

        cout << sizeof(long long) << endl;

        cout << sizeof(a) << endl;

        cout << sizeof(b) << endl;

        cout << sizeof(c) << endl;

        cout << sizeof(d) << endl;

        return 0;

    }

    #include <iostream>

    #include <iomanip>

    #include <cmath>

    using namespace std;

    int main()

    #define eps 1e-7

    // float 0000 4bytes

    /// double 00000000 8bytes

    // if you want to solve the question,must use double ,or you will miss the acuracy

    // to judge the accuration of float, please make it minus in a small range

    {

        float a = 13.1415926f;

        double b = 13.1415926;

        cout << setprecision(10) << a << endl;

        cout << setprecision(10) << b << endl;

        a = 13.1415926f;

        b = 13.141592611111111111;

        cout << setprecision(10) << a << endl;

        cout << setprecision(30) << b << endl; // if you make it out of range ,can still display the wrong number

        cout << sizeof(a) << endl;

        cout << sizeof(b) << endl;

        double c = 1.5e5; // 1.5*10^5

        cout << c << endl;

        double d = 1.5e-5; // 1.5*10^-5

        cout << d << endl;

        double x = 1.0 / 123123111123123123 * 123123111123123123; // when the float is large enough,must will have the error

        cout << x << endl;

        if (fabs(x – 1) < 0.00000001)

        {

            cout << “one two” << endl;

        }

        if (fabs(x – 1) < eps)

        {

            cout << “one two” << endl;

        }

        return 0;

    }

  • 补码

    补码是计算机表示有符号整数的一种方式,核心作用是把 “减法” 变成 “加法”,让计算机只用 “加法器” 就能处理加减运算。下面用最通俗的方式解释:

    一、为什么需要补码?

    计算机里用二进制存数,有符号数的最高位是符号位0 表示正数,1 表示负数)。如果直接用 “符号位 + 原码”(比如 +3 是 0011-3 是 1011),做减法会很麻烦(比如 3-2 要专门设计减法逻辑)。

    补码的巧妙之处:用 “加法” 代替 “减法”。比如 3-2 可以变成 3 + (-2),只要给 -2 一个特殊的 “补码”,让加法的结果等价于减法,计算机就只需 “加法器” 即可。

    二、补码的计算规则

    • 正数的补码:和原码完全相同
      例:+5 的原码是 00000101(8 位),补码也是 00000101
    • 负数的补码:分两步(或用 “模” 理解):
      • 方法 1(步骤法):原码的符号位不变数值位取反,然后加 1
        例:求 -5 的补码:
        ① 原码:10000101(符号位 1,数值位 0000101);
        ② 数值位取反:1111010
        ③ 加 1:1111011
        ④ 最终补码:11111011(符号位保留 1)。
      • 方法 2(模的概念):补码 = 模 – 数的绝对值(更直观)。
        对于 8 位二进制,“模” 是 2⁸ = 256(因为 8 位最多表示 256 个数)。
        所以 -5 的补码 = 256 - 5 = 251,二进制是 11111011(和步骤法结果一致)。

    三、补码如何让 “减法变加法”?

    以 3-2 为例,等价于 3 + (-2)

    • 3 的补码:00000011(正数,补码 = 原码);
    • -2 的补码:用 “模 256 – 2” 得 254,二进制 11111110
    • 两者相加:00000011 + 11111110 = 100000001
    • 因为是 8 位,最高位的 1 会 “溢出”(超出 8 位范围),最终结果取低 8 位 00000001,即 1,和 3-2=1 一致。

    四、特殊情况:-128(8 位补码)

    8 位补码的范围是 -128 ~ 127。其中 -128 比较特殊:它没有 “原码”(因为原码表示范围是 -127 ~ 127),但补码可以表示为 10000000(用 “模 256 – 128 = 128”,二进制 10000000)。

    总结

    补码的核心是用加法代替减法,让计算机硬件更简单。记住:

    • 正数补码 = 原码;
    • 负数补码 = 模 – 绝对值(或 “符号位不变,数值位取反加 1”);
    • 计算时,直接用补码相加,结果自然等价于原数的加减。