文章

难倒AI的一道C++入门练习题-20250216

前言

本文目的:在日常中为孩子们介绍AI领域的最新进展,顺带『纠偏』一些错误的认知。

背景

快要开学了,学校信奥培训群里开启了【每日一练】模式。

学习重在日常积累,往往在一些很简单的细节,就看你能否从中挖掘出有价值的点。

虽然是非常简单的入门题,但稍微拓展一下就很有意思。

注意:教、学编程,重点是思维方法,而不是“语法”。
“语法”完全可以自学,也应该自学。

于是,考验了一下孩子,也顺带考验了一下几个 AI 模型。

如果对AI模型的情况不感兴趣,

可以忽略中间各AI模型回答的过程,

直接看结论。

入门练习 题目

image-rxbh.png

这道题很简单,看题目中(L3)字样,貌似对应某个C/C++认证的 L3 级别。

题外,这些所谓认证好比参加围棋级位赛、段位赛
——得先从25级开始考,一个月一级,拿到1级证书才能考业余1段,以此类推。
(各地差异,有的省市只需要从15级或9级开始考)
表面说是“普及”,本质就是扩大剪羊毛的范围,吃相很难看。
——如果有这个能力,为什么不能跳级?反正达不到要求,过不了测评,对吗?

推测练习的目的是让学生熟练掌握 if-else 多条件分支。

在此之上,我们加点儿难度——先按题目要求实现,然后优化:

不能使用 if-else 条件分支、三目运算符、switch,不能使用数组,代码清晰、准确,尽可能优化。

——这要求其实不算高,但小小的考验代码能力和推理能力。

参赛选手

邀请了几位 AI 选手作为陪练:

  1. DeepSeek v3 和 R1

  2. Kimi

  3. 字节豆包

  4. 阿里千问

  5. 腾讯混元

  6. 讯飞星火

  7. ChatGPT/GPT4o/mini 1 Preview

第一轮作答

第一轮都没问题,答案大同小异,中规中矩,选部分有代表性的选手的答案展示如下:

字节豆包

#include <iostream>
using namespace std;

int main() {
    int student_id;
    // 读取输入的学号
    cin >> student_id;

    // 获取学号的尾数
    int last_digit = student_id % 10;

    // 根据尾数判断组号
    if (last_digit == 1 || last_digit == 4 || last_digit == 7) {
        cout << 1 << endl;
    } else if (last_digit == 2 || last_digit == 5 || last_digit == 8) {
        cout << 2 << endl;
    } else {
        cout << 3 << endl;
    }

    return 0;
}

Kimi

#include <iostream>
using namespace std;

int main() {
    int studentID;
    cin >> studentID; // 输入学号

    // 获取学号的尾数
    int lastDigit = studentID % 10;

    // 根据尾数判断组别
    if (lastDigit == 1 || lastDigit == 4 || lastDigit == 7) {
        cout << 1 << endl; // 输出第1组
    } else if (lastDigit == 2 || lastDigit == 5 || lastDigit == 8) {
        cout << 2 << endl; // 输出第2组
    } else {
        cout << 3 << endl; // 输出第3组(包含尾数为0、3、6、9的情况)
    }

    return 0;
}

其它选手就不展示了,完全一模一样,最多变量名和命名规则略有差异,比如豆包是 python 风格,kimi 是 c/c++ 的驼峰命名风格。

DeepSeek V3

#include <iostream>
using namespace std;

int main() {
    int studentId;
    cin >> studentId;  // 输入学号

    int lastDigit = studentId % 10;  // 获取学号的最后一位数字

    if (lastDigit == 1 || lastDigit == 4 || lastDigit == 7) {
        cout << 1 << endl;  // 第1组
    } else if (lastDigit == 2 || lastDigit == 5 || lastDigit == 8) {
        cout << 2 << endl;  // 第2组
    } else if (lastDigit == 3 || lastDigit == 6 || lastDigit == 9 || lastDigit == 0) {
        cout << 3 << endl;  // 第3组
    }

    return 0;
}

评论:中规中矩,与前两位 AI 同学差不多——但,最后一个 else if 条件判断是多余的

DeepSeek R1 深度思考

一大串【心路历程】就跳过不粘贴了,太长了。直接上结果:

#include <iostream>
using namespace std;

int main() {
    int num;
    cin >> num;
    int digit = num % 10;
    int group[] = {3, 1, 2, 3, 1, 2, 3, 1, 2, 3};
    cout << group[digit] << endl;
    return 0;
}

好吧,也算聪明,用了数组的小技巧,第一轮中属于优秀

类选手

下面是人类选手作答:

  1. 先对10求模获得尾数(个位数字)——各位 AI 同学一样正确

  2. 再用尾数进一步对3求模,初步获得分组数字——各位 AI 同学这里用条件分支,R1用数组

  3. 最后用三目表达式修正余数为0的情况。

各位 AI 同学的代码——说实话,哪位老师这么教学生,我立马要求退费。

某人:不服,这是按 L3 的教学要求掌握 if-else !

打脸:L3 没教变量么?那么多输出不能合并成一句? cout << group << endl;

——偏偏看群里其它同学们的答案,显然老师就是这么教的。

——个别同学明显是在其它机构学习的,答案也一样。

记住:我们学编程不是为了成为【编程爱好者】,这方面关键是训练严谨性。

自学多好,锻炼学习能力,还节约时间。

#include <iostream>
using namespace std;
int main()
{
    int id;
    cin >> id;
    if (id < 1 || id > 49) // 范围检查
        return -1;
    // 求学号的尾数(个位)
    int lastDigit = id % 10;
    // 对尾数求 3 的余数,作为组号
    int group = lastDigit % 3 == 0 ? 3 : lastDigit % 3; // 利用三目运算符简化判断
    cout << group;
    return 0;
}

各位 AI 同学,不知道是不是一样的训练数据,必须上难度,进入第二轮。

第二轮作答

要求不能使用条件分支、switch、三目运算符和数组。

这时,个别 AI 模型出问题了——忘了刚才聊啥,直接答非所问。

显然,AI 的会话衔接出了问题。

可是,一年多了还这样,很不应该啊!

字节豆包刚出来的时候曾经这样,但最近几个月已经飞速成长。

但讯飞星火、腾讯混元,你们一直在摸鱼么?

字节豆包

#include <iostream>

int main() {
    int student_id;
    std::cin >> student_id;
    int last_digit = student_id % 10;
    int group = 1 + (last_digit + 2) / 3;
    std::cout << group << std::endl;
    return 0;
}

思路正确,答案错误。

而且,重新问,第7行有所变化,但依然是错的:

int group = ((student_id - 1) % 3) + 1;

Kimi

它先回答了一个临时答案,同时继续优化,尝试去掉三目运算符,给出最终答案。

整个过程有点儿“思维链”的意思,自问自答、自我否定,深入推导,最终达到目的。

但,前面的临时答案不仅使用了三目运算符,关键是数学计算还错了

#include <iostream>
using namespace std;

int main() {
    int studentID;
    cin >> studentID; // 输入学号

    // 获取学号的尾数
    int lastDigit = studentID % 10;

    // 计算组号
    int group = (lastDigit % 3 == 0) ? 3 : (lastDigit + 2) / 3;

    cout << group << endl; // 输出组号

    return 0;
}

它继续优化,修改了关键的第 12 行,避免使用三目运算符,可惜数学部分还是错的

int group = (lastDigit % 3 == 0) * 3 + ((lastDigit + 2) / 3) * (lastDigit % 3 != 0);

惜败。

清华智谱

网页版 chat 有些小毛病,输出时代码没有正确的放在 MarkDown 格式的代码块中,导致格式混乱。

但 VSCode 中的插件 CodeGeeX 就没问题。速度快,质量好,第一次第二轮完美作答:

#include <iostream>
using namespace std;

int main() {
    int id;
    cin >> id;
    if (id < 1 || id > 49) // 范围检查
        return -1;

    // 求学号的尾数(个位)
    int lastDigit = id % 10;

    // 对尾数求 3 的余数,作为组号
    int group = (lastDigit + 2) % 3 + 1;

    cout << group;
    return 0;
}

阿里通义千问

(通义千问自动转到『代码模式』)

很意外,第一轮,第二轮都很棒,甚至加了数据验证(我教小朋友必须做数据验证)。

#include <iostream>
using namespace std;

int main() {
    int student_id;
    cin >> student_id;

    if (student_id < 1 || student_id > 49) {
        cout << "Invalid input. Please enter a number between 1 and 49." << endl;
        return 1;
    }

    int last_digit = student_id % 10;
    int group_number = (last_digit + 2) % 3 + 1; // 将尾数映射到组别

    cout << group_number << endl;

    return 0;
}

但,第二次测试,答案错误:

#include <iostream>

using namespace std;

int main() {
    int studentID;
    cin >> studentID; // 输入学生的学号

    // 获取学号的尾数,并将其调整到[0, 9]区间内
    int lastDigit = (studentID - 1) % 10;

    // 计算组号:每3个数字一组,加上1是为了将结果调整到[1, 3]区间内
    int groupNumber = (lastDigit / 3) + 1;

    // 特殊情况处理:如果尾数是0,应该属于第3组
    if (lastDigit == 9) {
        groupNumber = 3;
    }

    cout << groupNumber << endl;

    return 0;
}

第三次测试,又正确了。

——不稳定。

——不过,不是一个AI模型如此,是目前阶段,所有AI模型,的通病。原因在最后会解释。

DeepSeek V3

image-keul.png

DeepSeek V3 说它避免了三目运算符???

——幻觉?

——同样,幻觉不是一个AI模型的问题,是通病,不必苛责,更别盲目捧杀。

提醒它不能使用三目运算符,修正后的答案:

#include <iostream>
using namespace std;

int main() {
    int studentId;
    cin >> studentId;  // 输入学号

    int lastDigit = studentId % 10;  // 获取学号的最后一位数字

    // 利用数学公式计算组号
    int group = (lastDigit % 3) + (lastDigit % 3 == 0) * 3;
    cout << group << endl;

    return 0;
}

——正确!👍👍👍🌹🌹🌹

DeepSeek R1 深度思考

#include <iostream>
using namespace std;

int main() {
    int num;
    cin >> num;
    int digit = num % 10;
    int group = ((digit % 3) + 2) % 3 + 1; // 数学转换公式
    cout << group << endl;
    return 0;
}

好吧,第8行其实接近了,显然还需要进一步简化

int group = ((lastDigit % 3) + 2) % 3 + 1; // 数学转换公式

于是,引导它简化,可它又回到三目运算符的路线

——忘了前面的对话?这就有点儿低水平了

不得已,又重复强调要求。

它经过一番复杂的思考,坚定地给了最终答案:

int group = (141 >> (digit % 3 * 2)) & 3;+ 2) % 3 + 1; // 数学转换公式

看看它的思考过程,才是哭死——过程中其实已经得到了两个正确答案,但 ... 都被自己否决抛弃了:

image-hzgg.png

绿色框正确,蓝色框也正确但不是最优,红色框其实就是绿色框的答案,

它否决的原因是——它认为是原来的答案——又是幻觉?

其实,还是那个原因——AI并不真正理解“问题”和“答案”,不理解“知识”,甚至“不知道自己在干什么”。

经过引导的人类选手的答案

学习的本质是思考。

经过引导,人类选手采用了昨天新学的小技巧:利用 C++ 中 bool 值被视为整数0和1

(注意:可以这么做,但不推荐这种方法)进一步,利用余数的特性,省掉了逻辑判断。

下面的三行代码,将优化前后都放在一起,作为对比:

int group = lastDigit % 3 == 0 ? 3 : lastDigit % 3; // 利用三目运算符简化条件判断
int group = (lastDigit % 3) + 3 * (lastDigit % 3 == 0); // 利用逻辑值修正余数为 0 的情况
int group = (lastDigit + 2) % 3 + 1;    // 利用数学规律简化计算

小结:个人观点

个别模型一年多了还在摸鱼

——连完整对话都无法继续下去的那两位。

清华智谱最让我觉得意外——当年的ChatGLM3很惊艳,尤其本地部署。

当时同期的Qwen等,甚至LlamA等等在本地部署时各种低智表现,相对来说ChatGLM3又快又好——可现在网页版居然连输出格式都控制不好。

——不过VSCode中的插件CodeGeeX表现良好,甚至第二轮第一次就正确作答,代码能力不错👍

DeepSeek 的确有优势,但不明显

在多次清空会话测试中,也经常出现离谱的答案;

同样,其它模型在多次测试中,也有偶尔正确回答的情况,比如豆包、GPT4o、o1-mini 和 o1-Preview,甚至通义千问和Claude 3.5 Sonnet 第二轮第一次就答对了👍——重新再问又错了😂

AI没有本质上的突破

这一轮热潮从 ChatGPT 出现时,当时我测试后的结论——【AI模型甚至不理解它自己“说”的内容,更别说真正理解这些内容背后的各种『知识点』】,只是【调优策略,让你觉得它像真人一样和你聊天,甚至能顽梗——“让 AI 聊天时更有人味儿”】,这是【取巧/讨好】去迎合所谓的体验感,并不是真正意义上的的【智能】

所以,虽然真正人工智能的临界点可能随时到来——但还没有到来;

——这一切,与我二十五年前跟着老师尝试基于神经网络的人工智能时相比,没有本质上的突破

DeepSeek 有进步有优势,值得点赞,但不要盲目夸大

Google/Meta等开源时,我曾经推测:在算法、训练/推理/调优甚至数据集方面,都有很大的优化空间。尤其国内有几个团队在这些方面深入去钻研,迟早会出爆发性的成果。

——但,这样的成果,并不是那些媒体、自媒体、营销号【人云亦云】甚至【夸大、吹嘘】的那样的飞跃、突破。反而,是【现象级】的

——因为,无论其它公司,甚至 DeepSeek 自己,后续一定还会有新的、类似的突破。引爆了第一波的刚好是DeepSeek,不妨继续期待吧。

DeepSeek 究竟好不好?

DeepSeek V2发布没多久,我除了使用付费的 ChatGPT/Github Copilot,开始付费使用 DeepSeek 并推荐给朋友们——显然我很认可它

它很接近同期的 GPT4,而且很便宜,但它很慢,很罗嗦(按token计费)。当时我推测,它的慢有两种可能:1. 投入的推理算力资源不够;2. 模型推理效率不够。具体哪一种情况或者两种皆有,不知道。

但因为反应慢,我使用 DeepSeek 的时候很少——先用免费的,它们解决不了的问题,或者表现不尽如人意的时候,再使用 GPT4 和 DeepSeek。

所以,我使用 DeepSeek 更多是作为与GPT对比的样本,毕竟国产模型中我认为它是最接近GPT的,甚至比我很曾经期待的ChatGLM3/4还要好

另外,Qwen在本地部署中,出现了很多胡言乱语,表现还不如同级别的LlamA,可能是对推理算力要求较高的原因,在线版使用中没那么明显的问题。

市场影响

最近这波热潮,肯定极大的促进了某些机关国企采购 DeepSeek 的离线部署版本(及硬件)。说实话,以这些甲方的尿性,必然又要浪费很多经费了(上两轮大量闲置、淘汰的云存储、云计算,部分小县城甚至动辄几千万几亿砸在里面,却“通电即亏损”)。不过,其中拿来代替某些摸鱼的模型的,至少也算是进步吧。

“导致英伟达股价大跌”

这类的胡言乱语又蠢又坏,徒增笑尔

License:  CC BY 4.0