斯特林数C++实现:从数学原理到高精度计算与动态规划优化
1. 项目概述从数学理论到C实现斯特林数这个名字对于很多刚接触组合数学或者算法竞赛的朋友来说可能既熟悉又陌生。熟悉是因为它在很多高级算法和数学问题中频频现身比如划分问题、容斥原理、多项式转换陌生则是因为它的定义和计算方式确实有点绕尤其是第二类斯特林数涉及到集合划分理解起来需要一些抽象思维。我自己在最初学习的时候也花了不少功夫才把这两类数给捋清楚。简单来说斯特林数主要分为两类第一类斯特林数通常记作s(n, k)或c(n, k)和第二类斯特林数记作S(n, k)。它们都是描述将n个不同元素划分成k个部分的方案数但“部分”的定义截然不同。第一类关心的是“轮换”或者说“圆圈排列”而第二类关心的是“非空子集”。这个区别直接导致了它们在递推公式、生成函数乃至应用场景上的巨大差异。在C中实现它们的计算不仅仅是写几个循环那么简单它涉及到对大整数的处理、对递推关系的深刻理解以及对算法时间、空间复杂度的精细权衡。为什么我们要用C来实现斯特林数一方面C的高性能特性使其成为处理大规模组合计算例如n和k较大时的理想选择尤其是当我们需要将斯特林数作为子模块嵌入到更大的数值模拟或算法中时。另一方面通过亲手实现我们能更透彻地理解其数学本质比如递推关系的边界条件、数值的快速增长特性斯特林数增长极快很容易溢出基本数据类型以及如何利用动态规划、多项式技术进行优化。接下来我们就深入拆解这两类斯特林数的理论并一步步构建出稳健、高效的C计算模块。2. 斯特林数的数学理论核心解析要实现代码必须先吃透理论。斯特林数的定义是基石但更重要的是理解其背后的组合意义和推导逻辑这直接决定了我们实现算法的思路。2.1 第一类斯特林数轮换的艺术第一类斯特林数s(n, k)无符号表示将n个不同的元素划分成k个非空循环排列或称轮换的方法数。这里“循环排列”是关键。想象一下如果把一个排列首尾相连成一个圆圈那么旋转这个圆圈得到的被认为是同一种轮换。例如排列 (1,2,3) 和 (2,3,1) 在轮换意义下是相同的。它的递推公式来源于一个经典的组合构造思想考虑第n个元素如何加入。s(n, k) s(n-1, k-1) (n-1) * s(n-1, k) 其中 n, k 1。公式解读s(n-1, k-1)第n个元素独自形成一个新的轮换。这很好理解从前n-1个元素形成的k-1个轮换中再加入一个单元素轮换就构成了k个轮换。(n-1) * s(n-1, k)第n个元素插入到已有的k个轮换中去。一个包含m个元素的轮换有m个不同的“间隙”可以插入新元素因为轮换是环。对于前n-1个元素已经形成的k个轮换第n个元素可以插入到其中任何一个轮换的任何一个间隙。由于前n-1个元素总共有n-1个所以有n-1个间隙可供选择。边界条件是s(0,0)1,s(n,0)0 (n0),s(0,k)0 (k0)。无符号第一类斯特林数都是非负整数。注意还有一种带符号的第一类斯特林数其绝对值等于无符号第一类斯特林数符号为(-1)^(n-k)。在讨论生成函数特别是下降阶乘幂的展开时带符号的形式更常见。我们的实现将专注于更常用的无符号形式。2.2 第二类斯特林数集合的划分第二类斯特林数S(n, k)表示将n个不同的元素划分到k个非空且无标号的集合中的方法数。这里的“无标号”意味着{ {1,2}, {3} }和{ {3}, {1,2} }被视为同一种划分。它的递推公式同样基于对第n个元素的处理S(n, k) S(n-1, k-1) k * S(n-1, k) 其中 n, k 1。公式解读S(n-1, k-1)第n个元素独自成为一个新的集合。k * S(n-1, k)第n个元素放入已经存在的k个集合中的某一个。因为集合是无标号的但当我们具体放置时我们需要指定放入哪一个“具体的”集合。对于前n-1个元素已经形成的一种k集合划分第n个元素有k种选择。边界条件是S(0,0)1,S(n,0)0 (n0),S(0,k)0 (k0)。2.3 两类斯特林数的联系与区别理解它们的区别至关重要这能避免在应用时张冠李戴。核心区别第一类数对应“轮换”具有循环序第二类数对应“子集”没有内部顺序。这导致了递推公式中乘系数的不同第一类乘(n-1)与总元素数相关第二类乘k与当前集合数相关。数值增长对于固定的kS(n,k)的增长速度比s(n,k)快得多因为集合划分的方式通常多于轮换划分。当n和k都较大时两者的数值都会变得极其庞大。生成函数第二类斯特林数与下降阶乘幂x(x-1)...(x-k1)有直接关系而第一类带符号与普通幂x^n的展开有关。这是它们更深层的对偶性体现。3. C实现的核心策略与数据结构选择理论清晰后就要考虑如何在C中落地。直接使用递推公式是最直观的方法但面临两个主要挑战数值溢出和效率。3.1 应对大整数为什么必须用高精度斯特林数增长非常快。例如S(50, 10)已经是一个超过10^40的庞大数字远远超出了long long最大约9e18甚至__int128的表示范围。因此对于通用的、支持较大n和k的实现使用高精度整数大数库是必须的。方案选择C自带库标准库没有内置高精度整数。这是最大的障碍。第三方库如 GNU Multiple Precision Arithmetic Library (GMP)。功能强大性能极高是生产环境的首选。但对于学习目的或希望减少依赖的项目引入外部库可能稍显复杂。手动实现简单高精度为了深入理解并保证代码的纯粹性和可移植性我们可以自己实现一个用于非负整数加法和乘法的高精度类。这对于斯特林数计算主要是加法和乘法来说是可行的。我们的决策在本实现中我们将自己实现一个简易的BigInteger类仅支持非负整数的构造、加法、乘法、与普通整数的乘法以及输出。这能让我们聚焦于斯特林数算法的核心同时透彻理解大数运算在其中的作用。在实际需要高性能计算的项目中强烈建议替换为GMP等专业库。3.2 算法选择动态规划递推基于递推公式的计算本质上是一个动态规划DP问题。状态定义dp[i][j]存储s(i, j)或S(i, j)的值。状态转移直接套用递推公式。空间优化由于递推只依赖于前一行 (i-1) 的数据我们可以使用滚动数组将空间复杂度从 O(n*k) 优化到 O(k)。这对于n很大时节省内存非常有效。时间复杂度O(n*k)对于每一对(i, j)进行常数次大数运算。这是最平衡且易于实现的方法。虽然存在使用卷积和FFT快速傅里叶变换的 O(n log n) 方法来计算一整行的斯特林数但其实现复杂且对于单点或需要整个三角形的情况O(n*k) 的DP在n, k在几千范围内通常是更实际的选择。4. 手把手实现BigInteger类与斯特林数计算让我们开始编码。首先解决核心问题大整数。4.1 实现一个简易的BigInteger类我们将数字以十进制形式存储在std::vectorint中低位在前下标0存个位方便进位处理。#include iostream #include vector #include string #include algorithm #include cassert class BigInteger { private: std::vectorint digits; // 低位在前例如 123 存为 [3,2,1] void trim() { // 去除前导零 while (digits.size() 1 digits.back() 0) digits.pop_back(); } public: // 构造函数 BigInteger() {} BigInteger(long long num) { if (num 0) digits.push_back(0); while (num 0) { digits.push_back(num % 10); num / 10; } } BigInteger(const std::string str) { for (int i str.size() - 1; i 0; --i) { assert(isdigit(str[i])); digits.push_back(str[i] - 0); } trim(); } // 加法 BigInteger operator(const BigInteger other) const { BigInteger result; int carry 0; size_t maxSize std::max(digits.size(), other.digits.size()); result.digits.reserve(maxSize 1); for (size_t i 0; i maxSize || carry; i) { int sum carry; if (i digits.size()) sum digits[i]; if (i other.digits.size()) sum other.digits[i]; result.digits.push_back(sum % 10); carry sum / 10; } return result; } // 乘法大数 * 大数 BigInteger operator*(const BigInteger other) const { size_t len1 digits.size(), len2 other.digits.size(); std::vectorint temp(len1 len2, 0); for (size_t i 0; i len1; i) { int carry 0; for (size_t j 0; j len2; j) { temp[i j] digits[i] * other.digits[j] carry; carry temp[i j] / 10; temp[i j] % 10; } if (carry) temp[i len2] carry; } BigInteger result; result.digits temp; result.trim(); return result; } // 乘法大数 * 普通整数优化常用操作 BigInteger operator*(long long num) const { assert(num 0); if (num 0) return BigInteger(0); BigInteger result; long long carry 0; for (int d : digits) { carry d * num; result.digits.push_back(carry % 10); carry / 10; } while (carry) { result.digits.push_back(carry % 10); carry / 10; } result.trim(); return result; } // 输出 friend std::ostream operator(std::ostream os, const BigInteger num) { if (num.digits.empty()) os 0; else { for (auto it num.digits.rbegin(); it ! num.digits.rend(); it) os *it; } return os; } // 为了方便DP添加一个返回值为0的静态方法 static BigInteger zero() { return BigInteger(0); } static BigInteger one() { return BigInteger(1); } };这个类实现了我们需要的核心功能。注意为了性能operator*(long long)是单独实现的避免了先转换成BigInteger的开销。这在斯特林数递推的k * S(n-1, k)步骤中非常有用。4.2 实现第二类斯特林数计算DP 滚动数组我们先实现更常用的第二类斯特林数。使用滚动数组优化空间。#include vector std::vectorstd::vectorBigInteger stirling2_table(int max_n, int max_k) { // 返回一个 (max_n1) x (max_k1) 的表格S[n][k] 对应 s(n,k) // 注意当 k n 时值为0。 std::vectorstd::vectorBigInteger dp(max_n 1, std::vectorBigInteger(max_k 1, BigInteger::zero())); dp[0][0] BigInteger::one(); for (int n 1; n max_n; n) { // 边界条件 S(n,0)0 已经在初始化时设置好了 // k 只需要循环到 min(n, max_k)但为了表格完整我们全循环利用递推公式中的 k*S(n-1,k) 项当kn-1时S为0。 // 更高效的做法是循环到 min(n, max_k) int upper_k std::min(n, max_k); for (int k 1; k upper_k; k) { // S(n,k) S(n-1, k-1) k * S(n-1, k) BigInteger term1 dp[n-1][k-1]; // 注意dp[n-1][k] 可能超出当前计算范围当kn-1但我们的dp表已初始化为0所以安全。 BigInteger term2 dp[n-1][k] * k; // 使用我们优化的乘法 dp[n][k] term1 term2; } // 对于 k n 的部分dp[n][k] 保持为0 } return dp; } // 使用滚动数组的版本节省空间 BigInteger stirling2_single(int n, int k) { if (k 0 || k n) return BigInteger::zero(); if (n 0) return (k 0) ? BigInteger::one() : BigInteger::zero(); // 只维护两行prev 对应 n-1, curr 对应 n std::vectorBigInteger prev(k 1, BigInteger::zero()); std::vectorBigInteger curr(k 1, BigInteger::zero()); prev[0] BigInteger::one(); // S(0,0)1 // 注意对于 n‘0 这一行只有 prev[0]1其他 prev[j]0 (j0) for (int i 1; i n; i) { // 当前行 i 的边界是 min(i, k) int upper_j std::min(i, k); curr[0] BigInteger::zero(); // S(i,0)0 for i0 for (int j 1; j upper_j; j) { // 递推公式S(i,j) S(i-1, j-1) j * S(i-1, j) // prev 对应 i-1 BigInteger term1 prev[j-1]; // 当 j i-1 时prev[j] 本应为0。在我们的循环中upper_jmin(i,k) // 所以当 j i 且 i-1 j 时我们需要访问 prev[i]它可能不在prev的范围内因为prev大小是k1。 // 但幸运的是当 j i 时递推公式的第二项是 j * S(i-1, i)。由于 i-1 i S(i-1, i)0。 // 所以我们可以安全地认为如果 j i-1即 j i那么 prev[j] 在逻辑上为0。 BigInteger term2 (j i-1) ? (prev[j] * j) : BigInteger::zero(); curr[j] term1 term2; } // 交换准备下一轮迭代 std::swap(prev, curr); } // 循环结束后prev 对应的是 n 的结果因为最后交换了一次 return (k n) ? prev[k] : BigInteger::zero(); }滚动数组版本稍复杂因为它需要小心处理索引边界。stirling2_table函数更直观适合需要查询多次或获取整个三角形的情况但内存消耗大。stirling2_single适合单点查询内存效率高。4.3 实现第一类斯特林数计算第一类斯特林数的实现与第二类非常相似只是递推公式中的系数从k变成了(i-1)。// 计算无符号第一类斯特林数 s(n, k) 的表格 std::vectorstd::vectorBigInteger stirling1_table(int max_n, int max_k) { std::vectorstd::vectorBigInteger dp(max_n 1, std::vectorBigInteger(max_k 1, BigInteger::zero())); dp[0][0] BigInteger::one(); for (int n 1; n max_n; n) { int upper_k std::min(n, max_k); for (int k 1; k upper_k; k) { // s(n,k) s(n-1, k-1) (n-1) * s(n-1, k) BigInteger term1 dp[n-1][k-1]; BigInteger term2 dp[n-1][k] * (n - 1); // 注意系数是 (n-1) dp[n][k] term1 term2; } } return dp; } // 滚动数组版本计算单个 s(n, k) BigInteger stirling1_single(int n, int k) { if (k 0 || k n) return BigInteger::zero(); if (n 0) return (k 0) ? BigInteger::one() : BigInteger::zero(); std::vectorBigInteger prev(k 1, BigInteger::zero()); std::vectorBigInteger curr(k 1, BigInteger::zero()); prev[0] BigInteger::one(); for (int i 1; i n; i) { int upper_j std::min(i, k); curr[0] BigInteger::zero(); // s(i,0)0 for i0 for (int j 1; j upper_j; j) { BigInteger term1 prev[j-1]; // 注意系数是 (i-1) BigInteger term2 (j i-1) ? (prev[j] * (i - 1)) : BigInteger::zero(); curr[j] term1 term2; } std::swap(prev, curr); } return (k n) ? prev[k] : BigInteger::zero(); }4.4 测试与验证编写一个简单的main函数来测试我们的实现并与已知的小数值进行对比。int main() { int n 5, k 2; std::cout Testing Stirling Numbers of the Second Kind S(n, k):\n; auto tableS2 stirling2_table(5, 5); std::cout S( n , k ) tableS2[n][k] std::endl; std::cout Single query: S( n , k ) stirling2_single(n, k) std::endl; // 打印小三角形验证 std::cout \nS(n, k) triangle (n0..5):\n; for (int i 0; i 5; i) { for (int j 0; j i; j) { std::cout tableS2[i][j] ; } std::cout std::endl; } // 预期第二类斯特林数 S(5,2)15 // 三角形应为 // 1 // 0 1 // 0 1 1 // 0 1 3 1 // 0 1 7 6 1 // 0 1 15 25 10 1 std::cout \n\nTesting Stirling Numbers of the First Kind (unsigned) s(n, k):\n; auto tableS1 stirling1_table(5, 5); std::cout s( n , k ) tableS1[n][k] std::endl; std::cout Single query: s( n , k ) stirling1_single(n, k) std::endl; std::cout \ns(n, k) triangle (n0..5):\n; for (int i 0; i 5; i) { for (int j 0; j i; j) { std::cout tableS1[i][j] ; } std::cout std::endl; } // 预期无符号第一类斯特林数 s(5,2)50 // 三角形应为 // 1 // 0 1 // 0 1 1 // 0 2 3 1 // 0 6 11 6 1 // 0 24 50 35 10 1 // 测试一个更大的数展示大整数能力 std::cout \n\nTesting larger value (using single query to save memory):\n; int n_big 50, k_big 10; std::cout Calculating S( n_big , k_big )...\n; BigInteger result stirling2_single(n_big, k_big); std::cout S( n_big , k_big ) has result.toString().size() digits.\n; // 可以输出前几位和最后几位避免刷屏 // std::string resStr result.toString(); // std::cout First 20 digits: resStr.substr(0, 20) ...\n; return 0; }5. 性能优化、常见问题与实战心得实现基本功能后我们还需要关注效率、健壮性和实际应用中的技巧。5.1 性能瓶颈分析与优化方向大数运算开销这是最主要的性能瓶颈。我们实现的朴素大数乘法是 O(n^2) 的n为位数。当斯特林数值极大时位数可能上千计算会变慢。优化实现更高效的大数乘法如 Karatsuba 算法或 FFT 乘法。或者直接集成 GMP 库。递推计算O(n*k) 的时间复杂度对于n, k上万的情况可能压力较大。优化如果只需要单个S(n,k)递推无法避免。如果需要一整行S(n, *)可以利用第二类斯特林数与阶乘、伯努利数的关系通过卷积FFT在 O(n log n) 内求出但这非常复杂。并行化DP递推的行间是串行的但行内循环对j的循环理论上可以并行化因为计算curr[j]只依赖于prev[j]和prev[j-1]存在数据依赖。一种称为“波形前进”的方法可以实现一定程度的并行但实现复杂。内存访问使用滚动数组优化了空间但访问模式对缓存友好。我们的实现是顺序访问向量性能尚可。一个实用的建议对于n, k在几百到几千的量级使用滚动数组的DP配合一个优化过的BigInteger或GMP是完全可行的。如果数值更大就需要考虑更专业的数学库和算法。5.2 常见问题与调试技巧数值为0或错误检查边界条件确保dp[0][0]1正确设置。这是所有递推的起点。检查递推公式系数这是最容易出错的地方。第一类乘的是(n-1)第二类乘的是k。务必反复核对。验证小数据用n5的三角形与已知结果可以从组合数学资料或OEIS序列中查找手动对比这是最有效的调试方法。程序运行缓慢或内存不足使用滚动数组确保在计算单个值时使用了stirlingX_single函数而不是构建整个大表格。分析大数位数斯特林数增长极快。S(1000, 500)的位数是一个天文数字计算和存储它本身可能就不现实。需要根据实际需求设定合理的n, k上限。考虑取模运算在很多算法竞赛或应用中我们并不需要斯特林数的精确值而是需要它对一个大质数如1e97取模的结果。这可以彻底避免大数问题将所有运算放在模意义下进行速度极快。这时递推公式变为// 假设 mod 是一个全局常量如 const int MOD 1e97; S[n][k] (S[n-1][k-1] (long long)k * S[n-1][k]) % MOD; s[n][k] (s[n-1][k-1] (long long)(n-1) * s[n-1][k]) % MOD;这是工程中最常见的用法。BigInteger类的问题前导零确保trim函数在每次构造和运算后被正确调用否则输出可能会有前导零。乘法运算符重载确保实现了operator*(long long)和operator*(const BigInteger)并且优先级正确。5.3 实战心得与扩展思考预处理与缓存如果你的应用需要反复查询不同(n,k)的斯特林数且n, k的范围有限比如n, k 1000那么预先计算整个三角形表格并存储在内存或文件中是最高效的策略。虽然初始化耗时但之后的每次查询都是 O(1)。我们的stirlingX_table函数就是干这个的。空间与时间的权衡滚动数组节省了空间但如果你需要频繁查询不同n的值每次都要重新计算。表格法消耗 O(n*k) 空间但查询快。根据你的访问模式做选择。扩展到带符号第一类斯特林数如果需要带符号的第一类斯特林数s_signed(n, k) (-1)^(n-k) * |s(n,k)|可以在计算出无符号数后根据(n-k)的奇偶性添加符号。或者修改递推公式使用s_signed(n,k) s_signed(n-1,k-1) - (n-1)*s_signed(n-1,k)。关联其他组合数斯特林数与贝尔数所有划分的总数B_n sum_{k0}^n S(n,k)、伯努利数等都有密切联系。一个健壮的组合数学计算库往往会将这些函数一起实现。最后我想强调的是从数学公式到稳定高效的C代码这个过程最考验的是对细节的把握和对边界情况的处理。自己动手实现一遍哪怕是一个简单的BigInteger也会让你对斯特林数的理解远超仅仅记住公式。当你在更复杂的算法中比如利用斯特林数进行多项式变换或求解方程时这份扎实的实现会成为你可靠的基石。在实际项目中如果性能至关重要不要犹豫去集成像GMP这样的专业库它们经过千锤百炼远比自己实现的要快和稳。

相关新闻

AI降重工具评测与学术论文优化技巧

AI降重工具评测与学术论文优化技巧

1. AI降重工具的核心价值与学术应用场景论文降重是学术写作中绕不开的关键环节。去年帮导师审阅研究生论文时,我发现超过60%的修改意见都集中在重复率问题上。传统人工降重不仅耗时费力,还容易破坏原文的学术逻辑。现在AI工具已经能智能重组句式、替换学…

2026/10/17 22:34:16 阅读更多 →
【项目部署上线|第2篇】Spring Boot 项目打包成 jar 并在 Linux 运行

【项目部署上线|第2篇】Spring Boot 项目打包成 jar 并在 Linux 运行

前言 上一篇我们已经学习了 Linux 服务器的一些基础命令,比如目录操作、上传文件、查看进程、查看端口、查看日志等。 这一篇我们就正式把 Spring Boot 项目从本地打包成 jar 包,然后上传到 Linux 服务器运行。 这一步非常关键,因为项目部署上…

2026/10/19 13:37:56 阅读更多 →
微信本地数据库解密原理与实战:WechatDecrypt工具深度解析

微信本地数据库解密原理与实战:WechatDecrypt工具深度解析

1. 项目概述与核心价值最近在数据恢复和数字取证圈子里,一个叫 WechatDecrypt 的工具讨论度挺高。起因是不少朋友在换手机、重装系统或者手机意外损坏后,发现微信里那些重要的聊天记录、图片、文件找不回来了,或者想对本地存储的微信数据进行…

2026/10/19 13:46:46 阅读更多 →

最新新闻

lingbot-map:自然语言驱动的空间语义理解系统

lingbot-map:自然语言驱动的空间语义理解系统

1. “lingbot-map”不是地图SDK,而是一个语义驱动的空间认知原型系统第一次看到“lingbot-map”这个名字时,我下意识去查了主流地图服务商的开放平台文档、GitHub上热门的地理可视化库,甚至翻了几个开源GIS项目的命名惯例——结果一无所获。它…

2026/10/21 4:15:42 阅读更多 →
思维链原理与三大模型实测:从Prompt到Agent多步推理落地指南

思维链原理与三大模型实测:从Prompt到Agent多步推理落地指南

思维链这个词,这两年在大模型圈子里几乎是绕不开的热词。我自己在调Agent、做复杂任务拆解的时候,也明显感受到:同一个模型,用不用思维链,效果差距就像实习生直接交作业和逐步汇报思路之间的差距。很多朋友问我说Claud…

2026/10/21 4:15:42 阅读更多 →
人脸识别实战指南:从One-Shot学习到工程部署踩坑总结

人脸识别实战指南:从One-Shot学习到工程部署踩坑总结

人脸识别这块内容,我在整理某知名深度学习公开课程的笔记时反复啃过好几遍。课程原话讲得精简,逻辑也很清晰,但真到项目里去落地,中间会冒出不少课程里没有细讲的工程细节。这篇文章把我对课程笔记的深入理解、在实际项目中补充验…

2026/10/21 4:15:42 阅读更多 →
YOLOv5s部署实战:PyTorch转ONNX再到OpenVINO的CPU推理全流程

YOLOv5s部署实战:PyTorch转ONNX再到OpenVINO的CPU推理全流程

最近刚把一个 YOLOv5s 目标检测模型完整走了一遍部署链路:从 PyTorch 预训练权重转成 ONNX,再用 OpenVINO 变成推理加速模型,最后在 Windows 10 上用 Python 做实际推理测试。整个过程在 CPU 上完成,没有碰 GPU,效果却…

2026/10/21 4:15:42 阅读更多 →
用Metal优化Transformer推理:从CPU 4.9到GPU 31.5 tok/s的完整实践

用Metal优化Transformer推理:从CPU 4.9到GPU 31.5 tok/s的完整实践

把Transformer模型的推理链路整体搬到苹果芯片的GPU上,用Metal从头组织计算图和算子,这件事我从去年底开始做,前后改了四版。最终效果是解码吞吐从CPU路线的个位数涨到了30 tokens/s,同一个约1.1B参数的decoder-only模型&#xff…

2026/10/21 4:15:42 阅读更多 →
系统化提升个人技能:从技能地图到学习闭环

系统化提升个人技能:从技能地图到学习闭环

今年我陆续和朋友聊了十几场关于个人成长的私话,发现大家焦虑的点出奇一致:不是没在学,而是学的东西太多太散——今天刷两节剪辑课,明天收藏几个AI工具,后天又报名一个Excel进阶班,忙活大半年,最…

2026/10/21 4:14:42 阅读更多 →

日新闻

统一内存+量化:锐龙AI Max PRO 400如何本地跑320B大模型

统一内存+量化:锐龙AI Max PRO 400如何本地跑320B大模型

这段时间硬件圈和AI圈都在传一个事:AMD锐龙AI Max PRO 400系列把最高192GB统一内存搬进了PC形态的产品里,按宣传口径,本地跑320B参数的大家伙不再是纸面概念。我第一反应倒不是“内存真大”,而是这话背后的含金量——它把过去只能…

2026/10/21 0:00:11 阅读更多 →
AI助手深度使用体验:对话质量、长文本处理与指令遵循如何留住用户

AI助手深度使用体验:对话质量、长文本处理与指令遵循如何留住用户

1. 从“封号重开”这个行为说起:用户到底在追求什么“封号重开”这四个字,放在任何产品语境里都带着一股决绝的味道。一个账号从零开始积累使用记录、调教偏好、沉淀工作流,背后是大量的时间和精力成本。正常情况下,没有人愿意主动…

2026/10/21 0:00:11 阅读更多 →
ROS中YOLOv3工程落地:通信同步、坐标变换与性能调优

ROS中YOLOv3工程落地:通信同步、坐标变换与性能调优

1. 为什么在ROS里硬刚YOLOv3不是“炫技”,而是工程落地的必经之路我第一次在某高校机器人实验室看到那台搭载Jetson TX2的移动底盘原地打转、反复识别错垃圾桶时,就意识到:单纯跑通darknet_ros demo和真正让YOLOv3在ROS里“干活”&#xff0c…

2026/10/21 0:00:11 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/20 20:43:59 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 10:02:08 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:45 阅读更多 →