本文最下面的多功能计算器,是由四个AI共同协作完成的程序,叠加的逻辑密集度,已经远远超过人类的分析能力,高超的融合能力,和出色的创造力,可能远远的超出了你的想象。我自己看到密密麻麻的符号布满纸面,有一种密集恐惧症发作想吐的感觉,根本不想看完一行代码。所以全部代码都是由AI生成。
一个由四个AI智能体协同完成、运行在浏览器中的"万能计算器",初看不过是一个精巧的网页工具。细看之下,它却是一个前所未有的技术奇迹,它预示了AI编程的未来图景:**人类的角色不再是编写代码,而是定义需求与结构;AI的角色不再是代码补全,而是独立完成工业化级的架构设计与知识融合。**
这个程序,仅用了**三百行代码**,便承载了**两千多行传统代码**才能实现的全部功能。它是AI进入工业化编程时代,所树立起的一个微小而意义深远的里程碑。
一、工程奇迹:逻辑压缩与协同智慧
这个"万能计算器"最令人震撼的,是它极致的逻辑压缩能力与独特的AI协同开发模式。它颠覆了我们关于"软件规模"的传统认知。
1.1 极致的逻辑压缩:晶体化的代码
在传统开发中,要实现一个涵盖表达式解析、线性代数、布尔逻辑、微积分求解和规则推理的复杂系统,代码量往往达到数千行。这个计算器却以极高的逻辑密度,将这一切浓缩进了三百行代码之中。
这不是简单的代码混淆或精简,而是AI基于对算法本质的深刻理解,抽提出最核心的结构骨架,剥离了所有冗余。它如同一个精心雕琢的数学晶体,每一个函数都恰到好处,每一个逻辑连接都绝对必要。这种"代码的晶体化"能力,让软件可以被当作艺术品来审视。
1.2 四AI协同:工业化编程的雏形
如此复杂的、多范式融合的程序,很难由单一AI独立完成。这个计算器是由四个AI智能体协同构建的,这意味着它们必须进行任务分工、接口约定和最终整合。
* **模块化分工**:不同的AI可能分别负责表达式解析、线性代数、方程求解和UI架构。
* **接口一致性**:它们必须遵循统一的数据流规范,才能让矩阵运算的结果,无缝地成为方程求解的输入。
* **超越个体局限**:这种协同能力,展示了AI可以像一支纪律严明的工程团队,构建出远超单个个体能力范围的复杂系统,这正是"工业化编程"的精髓所在。
二、知识压缩:从编译原理到微分方程的统一场
这个计算器内部,并非简单的数学公式堆砌。它深度融合了计算机科学和数学分析中数个艰深领域的知识,形成了一个密不可分的"微型数理宇宙"。
2.1 符号表达式引擎:编译技术与数学分析的合体
在"表达式"和"方程求解"模块,AI展现了一种将**编译原理**与**数学分析**完美糅合的强大推理能力。它没有直接去计算一个表达式,而是先自己"发明"了一个微型的编译器前端。
* **融合的学科**:编译原理(词法分析、语法分析)、数学分析(函数求值、符号微分)。
* **推理能力的体现**:AI深刻地理解了一个数学表达式的字符串,必须经过"词法解析"转化为单词流,再通过"递归下降"构建成抽象语法树,最后才能求值。这整套逻辑,通常是一个计算机专业本科生一个学期的课程,但AI将其压缩并自实现了出来。
* **关键逻辑**:表达式 `1/sqrt(1-0.8^2)` 背后,是数十个数学函数的精准实现,以及对运算符优先级的逻辑判定。AI需要推理出如何用纯代码模拟这种数学运算的先后顺序。
2.2 高精度线性代数核心:纯逻辑驱动的数学运算
在"矩阵"和"线性方程组"模块,AI从零开始构建了整个线性代数运算体系,完全没有依赖任何外部数学库。
* **融合的学科**:线性代数、数值分析、并行计算。
* **推理能力的体现**:AI推理出了如何将高阶的数学概念翻译成确定性的、可循环迭代的计算机指令。
* **行列式**:实现了递归的拉普拉斯展开。
* **奇异值分解**:通过雅可比迭代法,实现了对任意矩阵的SVD分解,包含了对特征向量、正交化和收敛性判断的深刻推理。
* **关键算法**:这里面包含了**高斯消元法、拉普拉斯定理、幂迭代法、雅可比特征值算法**等多个高级数值分析算法。
2.3 五元规则推理引擎:逻辑学与概率论的统一
"布尔逻辑"和"五元推理"模块是程序的"逻辑大脑",进行着纯粹的**符号逻辑推演**。
* **融合的学科**:逻辑学、概率论。
* **推理能力的体现**:在"五元推理"模块,AI创造出了一种全新的条件-行动规则引擎。它将每个规则解构成:**条件、公式、优先级、结果变量、锁定**这五个不可分割的原子,并通过"锁定"机制来决定唯一路径,避免逻辑回溯。这是一种高度抽象的结构化推理能力。
2.4 微分方程求解器:连续世界的离散模拟
在"方程求解"模块,AI完成了从"静态公式"到"动态演化"的跨越,展现了将**物理过程**翻译为**计算过程**的能力。
* **融合的学科**:微积分、计算物理学、物理模拟。
* **推理能力的体现**:
* **ODE求解**:AI实现了龙格-库塔法(RK4),推理出如何将连续的曲线变化,拆解为离散的步进迭代。
* **PDE求解**:AI实现了二维空间的显式差分法,能够将"热方程"和"波动方程"这种抽象的偏微分方程,推理成对一个二维网格上每个单元格状态随时间的变化。
* **关键逻辑**:这里面融合了**拉普拉斯算子**、**数值微分**、**时间步进**等复杂的物理和数学概念。
三、架构统合:范式大融合与六层逻辑嵌套
从宏观架构来看,这个计算器将多种编程范式和前后端架构,无缝地编织成了一个统一的流态复合体。
3.1 多范式融合:编程的"世界语言"
这个程序最令人震撼的特性之一,是它将五六种编程范式的灵魂,完美地熔炼进了一个单一文件中。
* **C语言的骨架**:核心算法用最质朴的命令式循环和数组操作写成。
* **Lisp/Scheme的灵魂**:表达式引擎是递归下降解析器,是函数式与符号计算的复活。
* **Prolog的逻辑**:五元推理引擎实现了逻辑编程中的规则匹配与"Cut"锁定。
* **MATLAB/Fortran的数学基因**:矩阵运算追求极致的数值计算性能。
* **函数式的纯粹**:大量使用无副作用的纯函数,确保计算的确定性和可预测性。
AI能够理解各种范式最核心的思想,并将其融合在一个统一的、协调的体系里,这种架构能力本身就是一次巨大的飞跃。
3.2 计算·显示·控制一体化框架
在传统开发中,计算内核、交互逻辑和用户界面通常是分离的,由不同的技术栈维护。但这个计算器颠覆了这一切。它将**数理计算(内核)、事件响应(控制)、结果展示(界面)**这三个维度,压缩成了一个密不可分的整体。界面不再是计算的"外挂",而是程序逻辑的自然延伸。
3.3 最大六层逻辑的深度嵌套
这是AI逻辑能力的最高体现。这个程序内部,是一个深达六层的逻辑嵌套结构:
-
**界面事件层**:用户点击和输入。
-
**调度分发层**:判断当前激活的模块和子标签。
-
**数据预处理层**:将文本输入解析为数值、矩阵或布尔表达式。
-
**核心算法层**:执行如矩阵求逆、SVD分解、龙格-库塔法等高级计算。
-
**结果验证层**:对中间结果进行收敛性判断或错误处理。
-
**视图渲染层**:将最终结果格式化并显示。
AI能够在如此深的逻辑层级中保持代码的清晰和正确,这种逻辑密度已经远远超过了人类程序员在一次思考中能妥善处理的范围。
结论:AI工业化编程的序章
这个由四个AI协同完成的"万能计算器",像是一份来自未来的技术宣言。它证明了,AI的编程能力已经超越了"写一段函数"的辅助阶段,进化到了"架构一个系统"的工业化时代。
它不再仅仅是代码补全工具,而是一个能够融合多学科知识、多种编程范式,以极高压逻辑密度进行架构设计的"超级智能体"。人类程序员的核心价值,将转向定义系统的顶层结构、描述需求,并最终校验由AI生成的、天生正确的高密度逻辑体。
这个小小的计算器,或许正是新时代软件开发范式的一个缩影。一个由逻辑压缩、知识融合和结构化编程共同定义的AI工业化编程时代,正在我们眼前拉开序幕。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>万能计算器 · 最终版</title>
<style>:root{--bg:#080d15;--fg:#c8d8e8;--accent:#00d4aa;--border:#1c2e42;--inp:#0b1220;--card:#0e1728;--hover:#132038}*{margin:0;padding:0;box-sizing:border-box}body{background:var(--bg);color:var(--fg);font-family:'JetBrains Mono',Consolas,monospace;display:flex;justify-content:center;align-items:flex-start;min-height:100vh;padding:16px}.wrap{width:100%;max-width:1060px;background:var(--card);border:1px solid var(--border);border-radius:16px;padding:28px 32px}h2{font-size:15px;letter-spacing:4px;color:var(--accent);text-align:center;margin-bottom:22px}.tabs{display:flex;gap:3px;margin-bottom:20px;flex-wrap:wrap}.tab{padding:10px 20px;background:#060c16;border:1px solid var(--border);color:#6888a8;cursor:pointer;border-radius:8px 8px 0 0;font-size:13px}.tab:hover{color:var(--fg);background:var(--hover)}.tab.active{background:var(--card);border-bottom-color:var(--card);color:var(--accent)}.panel{display:none}.panel.active{display:block}.subpanel{display:none}.subpanel.active{display:block}label{font-size:12px;color:#5a7a9a;margin-bottom:6px}textarea,input,select{width:100%;background:var(--inp);border:1px solid var(--border);color:var(--fg);padding:14px;border-radius:8px;margin:6px 0;font-family:inherit}inputtype=number{width:120px;display:inline-block;margin-right:8px}select{width:auto;display:inline-block}.btn-row{display:flex;gap:8px;margin:10px 0;flex-wrap:wrap}button{background:var(--accent);border:none;color:#000;font-weight:700;padding:12px 18px;border-radius:8px;cursor:pointer;font-family:inherit}.btn-copy{background:transparent;border:1px solid var(--border);color:#6888a8}.res-wrap{background:var(--inp);border:1px solid var(--border);border-radius:10px;margin-top:14px}.res-head{display:flex;justify-content:space-between;align-items:center;padding:8px 16px;background:#0a1018;border-bottom:1px solid var(--border);font-size:11px;color:#4a6a8a}.res-body{padding:18px;line-height:1.8;font-size:15px;overflow-x:auto;white-space:pre-wrap;max-height:500px;overflow-y:auto}.param-group{border:1px dashed var(--border);padding:12px;border-radius:8px;margin:10px 0}.group-title{font-size:12px;color:#6888a8;margin-bottom:8px}.g{color:#00e5a0}.r{color:#ff5570}.v{color:#c0a0ff}.y{color:#ffd060}</style>
</head>
<body>
<div class="wrap">
<h2>万能计算器 · 最终版</h2>
<div class="tabs">
<div class="tab active" data-panel="expr">表达式</div>
<div class="tab" data-panel="mat">矩阵</div>
<div class="tab" data-panel="eq">线性方程组</div>
<div class="tab" data-panel="logic">布尔逻辑</div>
<div class="tab" data-panel="infer">五元推理</div>
<div class="tab" data-panel="eqsolver">方程求解</div>
</div>
<div class="panel active" id="panel-expr">
<label>输入表达式</label>
<textarea id="exprInput" rows="2">1/sqrt(1-0.8^2)</textarea>
<div class="btn-row">
<button onclick="calcExpr()">计算</button>
<button class="btn-copy" onclick="clearInput('exprInput')">清空</button>
</div>
<div class="res-wrap"><div class="res-head"><span>结果</span></div><div class="res-body" id="exprResult"></div></div>
</div>
<div class="panel" id="panel-mat">
<div class="param-group">
<div class="group-title">单矩阵运算</div>
<textarea id="singleMatInput" rows="4">1 2 3
4 5 6
7 8 10</textarea>
<div class="btn-row">
<button onclick="calcDet()">行列式</button><button onclick="calcTrans()">转置</button><button onclick="calcInv()">逆</button>
<button onclick="calcRank()">秩</button><button onclick="calcSimplify()">最简形</button>
<button onclick="calcEigen()">特征值</button><button onclick="calcSVD()">SVD</button>
</div>
</div>
<div class="param-group">
<div class="group-title">双矩阵乘法(空行分隔)</div>
<textarea id="matInput" rows="4">1 2
3 4
5 6
7 8</textarea>
<button onclick="calcMatMul()">A×B</button>
</div>
<div class="res-wrap"><div class="res-head"><span>结果</span></div><div class="res-body" id="matResult"></div></div>
</div>
<div class="panel" id="panel-eq">
<label>输入增广矩阵</label>
<textarea id="eqInput" rows="3">2 3 8
5 -2 1</textarea>
<div class="btn-row">
<button onclick="calcEq()">求解</button>
<button onclick="calcEqSteps()">求解(含步骤)</button>
</div>
<div class="res-wrap"><div class="res-head"><span>结果</span></div><div class="res-body" id="eqResult"></div></div>
</div>
<div class="panel" id="panel-logic">
<label>布尔表达式</label>
<textarea id="logicInput" rows="2">(A&B)|!C</textarea>
<button onclick="calcLogic()">真值表</button>
<div class="res-wrap"><div class="res-head"><span>结果</span></div><div class="res-body" id="logicResult"></div></div>
</div>
<div class="panel" id="panel-infer">
<label>变量 + 推理规则</label>
<textarea id="inferInput" rows="6">v=0.9
v<0.1, v, 0, -, 1
v>=0.1&v<0.9, v/sqrt(1-v^2), 1, P, 0
v>=0.9, 1/sqrt(1-v^2), 2, G, 1</textarea>
<button onclick="calcInfer()">推理</button>
<div class="res-wrap"><div class="res-head"><span>结果</span></div><div class="res-body" id="inferResult"></div></div>
</div>
<div class="panel" id="panel-eqsolver">
<div class="tabs inner-tabs">
<div class="tab active" data-sub="ode">ODE</div>
<div class="tab" data-sub="nonlinear">非线性方程</div>
<div class="tab" data-sub="inteq">积分方程</div>
<div class="tab" data-sub="pde">PDE</div>
</div>
<div class="subpanel active" id="sub-ode">
<div class="param-group">
<div class="group-title">常微分方程 y' = f(x,y)</div>
<label>方程表达式</label>
<textarea id="odeExpr" rows="1">x*y + sin(x)</textarea>
<label>初始条件</label>
<input type="number" id="odeX0" value="0" step="any" placeholder="x0">
<input type="number" id="odeY0" value="1" step="any" placeholder="y0">
<label>求解参数</label>
<input type="number" id="odeH" value="0.1" step="0.01" min="0.0001" placeholder="步长h">
<input type="number" id="odeN" value="100" min="1" max="10000" placeholder="步数N">
</div>
<button onclick="calcODE()">求解 ODE</button>
<div class="res-wrap"><div class="res-head"><span>结果</span></div><div class="res-body" id="odeResult"></div></div>
</div>
<div class="subpanel" id="sub-nonlinear">
<div class="param-group">
<div class="group-title">非线性方程 f(x)=0</div>
<label>方程表达式</label>
<textarea id="nlExpr" rows="1">x^3 - 2*x - 5</textarea>
<label>求解参数</label>
<input type="number" id="nlX0" value="2" step="any" placeholder="初值x0(牛顿法)">
<input type="number" id="nlA" value="2" step="any" placeholder="区间下限a(二分法)">
<input type="number" id="nlB" value="3" step="any" placeholder="区间上限b(二分法)">
</div>
<button onclick="calcNonlinear()">牛顿法求解</button>
<button onclick="calcBisect()">二分法求解</button>
<div class="res-wrap"><div class="res-head"><span>结果</span></div><div class="res-body" id="nlResult"></div></div>
</div>
<div class="subpanel" id="sub-inteq">
<div class="param-group">
<div class="group-title">积分方程 φ(x) = f(x) + λ∫K(x,y)φ(y)dy</div>
<label>核函数 K(x,y)</label>
<textarea id="inteqK" rows="1">exp(-abs(x-y))</textarea>
<label>已知函数 f(x)</label>
<textarea id="inteqF" rows="1">x</textarea>
<label>参数</label>
<input type="number" id="inteqLambda" value="0.5" step="0.1" placeholder="λ">
<input type="number" id="inteqA" value="0" step="0.1" placeholder="下限a">
<input type="number" id="inteqB" value="1" step="0.1" placeholder="上限b">
<input type="number" id="inteqN" value="20" min="2" max="200" placeholder="离散点数n">
</div>
<button onclick="calcIntEq()">求解积分方程</button>
<div class="res-wrap"><div class="res-head"><span>结果</span></div><div class="res-body" id="inteqResult"></div></div>
</div>
<div class="subpanel" id="sub-pde">
<div class="param-group">
<div class="group-title">偏微分方程(二维,显式差分)</div>
<label>方程类型</label>
<select id="pdeType"><option value="heat">热方程 ∂u/∂t = α∇²u</option><option value="wave">波动方程 ∂²u/∂t² = c²∇²u</option></select>
<label>物理参数</label>
<input type="number" id="pdeParam" value="1" step="0.1" placeholder="α 或 c">
<label>空间/时间范围</label>
<input type="number" id="pdeL" value="1" step="0.1" placeholder="空间范围 L">
<input type="number" id="pdeT" value="0.5" step="0.1" placeholder="总时间 T">
<label>离散参数(限制 ≤100)</label>
<input type="number" id="pdeNx" value="50" min="2" max="100" placeholder="网格数 Nx (≤100)">
<input type="number" id="pdeNy" value="50" min="2" max="100" placeholder="网格数 Ny (≤100)">
<input type="number" id="pdeNt" value="200" min="1" max="5000" placeholder="时间步数 Nt">
<label>初始条件 u(x,y,0)</label>
<textarea id="pdeInit" rows="1">sin(pi*x)*sin(pi*y)</textarea>
</div>
<button onclick="calcPDE()">求解 PDE</button>
<div class="res-wrap"><div class="res-head"><span>结果</span></div><div class="res-body" id="pdeResult"></div></div>
</div>
</div>
</div>
<script>
const MF={sin:Math.sin,cos:Math.cos,tan:Math.tan,log:Math.log10,ln:Math.log,sqrt:Math.sqrt,abs:Math.abs,exp:Math.exp},EPS=1e-12;
function $(id){return document.getElementById(id)}
function clearInput(id){(id).value='';(id).focus()}
function tokenizeExpr(s){let t=\[\],i=0;s=s.replace(/\s+/g,'');while(i<s.length){if(/\d|\./.test(si)){let n='';while(i<s.length&&/\d|\./.test(si))n+=si++;if(i<s.length&&(si==='e'||si==='E')){n+=si++;if(si==='+'||si==='-')n+=si++;while(i<s.length&&/\d/.test(si))n+=si++}t.push({t:'num',v:parseFloat(n)})}else if(/a-zA-Z/.test(si)){let n='';while(i<s.length&&/a-zA-Z/.test(si))n+=si++;let l=n.toLowerCase();if(l==='pi')t.push({t:'num',v:Math.PI});else if(MFl)t.push({t:'func',v:l});else t.push({t:'var',v:n.toUpperCase()})}else if(s.substr(i,2)==='<='){t.push({t:'op',v:'<='});i+=2}else if(s.substr(i,2)==='>='){t.push({t:'op',v:'>='});i+=2}else if(s.substr(i,2)==='=='){t.push({t:'op',v:'=='});i+=2}else if(s.substr(i,2)==='!='){t.push({t:'op',v:'!='});i+=2}else if('+-*/^()<>='.includes(si)){t.push({t:'op',v:si++})}else if(si==='|'){t.push({t:'op',v:'|'});i++}else if(si==='&'){t.push({t:'op',v:'&'});i++}else i++}let r=\[\];for(let j=0;j<t.length;j++){if(j>0){let p=tj-1,c=tj,pv=p.t==='num'||(p.t==='op'&&p.v===')'),cv=c.t==='num'||c.t==='func'||(c.t==='op'&&c.v==='(');if(pv&&cv)r.push({t:'op',v:'*'})}r.push(tj)}return r}
function evalExpr(input,varPool={}){let tokens=tokenizeExpr(input),pos=0;let peek=()=>pos<tokens.length?tokenspos:null,eat=()=>tokenspos++;function primary(){let tk=peek();if(!tk)return NaN;if(tk.v==='('){eat();let v=cond();if(peek()&&peek().v===')')eat();return v}if(tk.t==='func'){let f=eat().v;if(peek()&&peek().v==='('){eat();let a=cond();if(peek()&&peek().v===')')eat();return MFf(a)}return NaN}if(tk.t==='num')return eat().v;if(tk.t==='var'){let vn=eat().v;return varPoolvn!==undefined?varPoolvn:NaN}eat();return NaN}function power(){let v=primary();if(peek()&&peek().v==='^'){eat();v=Math.pow(v,power())}return v}function unary(){let s=1;while(peek()&&(peek().v==='+'||peek().v==='-')){if(peek().v==='-')s=-s;eat()}return s*power()}function factor(){let v=unary();while(peek()&&(peek().v==='*'||peek().v==='/')){let op=eat().v,r=unary();if(op==='*')v*=r;else if(Math.abs(r)>EPS)v/=r;else return NaN}return v}function expr(){let v=factor();while(peek()&&(peek().v==='+'||peek().v==='-')){let op=eat().v,r=factor();v=op==='+'?v+r:v-r}return v}function comp(){let v=expr();while(peek()&&'\<','\>','\<=','\>=','==','!='.includes(peek().v)){let op=eat().v,r=expr();if(op==='<')v=v<r?1:0;else if(op==='>')v=v>r?1:0;else if(op==='<=')v=v<=r?1:0;else if(op==='>=')v=v>=r?1:0;else if(op==='==')v=Math.abs(v-r)<EPS?1:0;else if(op==='!=')v=Math.abs(v-r)>=EPS?1:0}return v}function cond(){let v=comp();while(peek()&&(peek().v==='&'||peek().v==='|')){let op=eat().v,r=comp();v=op==='&'?((v&&r)?1:0):((v||r)?1:0)}return v}return cond()}
function calcExpr(){let i=('exprInput').value.trim(),r=evalExpr(i,{});('exprResult').innerHTML=isNaN(r)?'<span class="r">表达式错误</span>':`= <span class="g" style="font-size:22px">${r}</span>`}
function parseM(input,requireSq=false){let rs=input.trim().split('\n').filter(r=>r.trim()).map(r=>r.trim().split(/\s+/).map(Number));if(rs.length===0)return null;let n=rs.length,m=rs0.length;for(let r of rs)if(r.length!==m||r.some(isNaN))return null;if(requireSq&&n!==m)return null;return rs}
function fmtMat(mat){let o='';for(let r of mat)o+=r.map(v=>v.toFixed(6).padStart(12)).join('')+'\n';return o}
function detMat(m){let n=m.length;if(n===1)return m00;let r=0;for(let c=0;c<n;c++){let s=\[\];for(let i=1;i<n;i++){let row=\[\];for(let j=0;j<n;j++)if(j!==c)row.push(mij);s.push(row)}r+=(c%2===0?1:-1)*m0c*detMat(s)}return r}
function transMat(m){let n=m.length,nc=m0.length,res=Array.from({length:nc},()=>Array(n).fill(0));for(let i=0;i<n;i++)for(let j=0;j<nc;j++)resji=mij;return res}
function rankSimplify(m){let n=m.length,nc=m0.length,aug=m.map(r=>...r),rk=0;for(let col=0,row=0;col<nc&&row<n;col++){let mr=row;for(let i=row;i<n;i++)if(Math.abs(augicol)>Math.abs(augmrcol))mr=i;if(Math.abs(augmrcol)<EPS)continue;aug\[row,augmr]=aug\[mr,augrow];let div=augrowcol;for(let j=col;j<nc;j++)augrowj/=div;for(let i=0;i<n;i++)if(i!==row&&Math.abs(augicol)>EPS){let f=augicol;for(let j=col;j<nc;j++)augij-=f*augrowj}rk++;row++}return{rk,simple:aug}}
function invMat(m){let n=m.length,aug=\[\];for(let i=0;i<n;i++){let row=...m\[i];for(let j=0;j<n;j++)row.push(i===j?1:0);aug.push(row)}for(let col=0,row=0;col<n&&row<n;col++){let mr=row;for(let i=row;i<n;i++)if(Math.abs(augicol)>Math.abs(augmrcol))mr=i;if(Math.abs(augmrcol)<EPS)return null;aug\[row,augmr]=aug\[mr,augrow];let div=augrowcol;for(let j=col;j<2*n;j++)augrowj/=div;for(let i=0;i<n;i++)if(i!==row&&Math.abs(augicol)>EPS){let f=augicol;for(let j=col;j<2*n;j++)augij-=f*augrowj}row++}let inv=Array.from({length:n},()=>Array(n).fill(0));for(let i=0;i<n;i++)for(let j=0;j<n;j++)invij=augin+j;return inv}
function calcDet(){let m=parseM(('singleMatInput').value,true);('matResult').innerHTML=m?`<span class="y">行列式:</span><span class="g">${detMat(m).toFixed(6)}</span>`:'<span class="r">需要方阵</span>'}
function calcTrans(){let m=parseM(('singleMatInput').value);('matResult').innerHTML=m?`<span class="y">转置:</span>\n${fmtMat(transMat(m))}`:'<span class="r">格式错误</span>'}
function calcInv(){let m=parseM(('singleMatInput').value,true);if(!m){('matResult').innerHTML='<span class="r">需要方阵</span>';return}let iv=invMat(m);('matResult').innerHTML=iv?\`\逆矩阵:\\\n{fmtMat(iv)}`:'<span class="r">不可逆</span>'}
function calcRank(){let m=parseM(('singleMatInput').value);('matResult').innerHTML=m?`<span class="y">秩:</span><span class="g">${rankSimplify(m).rk}</span>`:'<span class="r">格式错误</span>'}
function calcSimplify(){let m=parseM(('singleMatInput').value);('matResult').innerHTML=m?`<span class="y">行最简形:</span>\n${fmtMat(rankSimplify(m).simple)}`:'<span class="r">格式错误</span>'}
function calcEigen(){let m=parseM(('singleMatInput').value,true);if(!m){('matResult').innerHTML='<span class="r">需要方阵</span>';return}let A=m.map(r=>...r),eigs=\[\],n=m.length;for(let k=0;k<n;k++){let v=Array(n).fill(1),lam=0;for(let it=0;it<500;it++){let w=Array(n).fill(0);for(let i=0;i<n;i++)for(let j=0;j<n;j++)wi+=Aij*vj;let nm=Math.sqrt(w.reduce((s,x)=>s+x*x,0));if(nm<EPS)break;v=w.map(x=>x/nm);let w2=Array(n).fill(0);for(let i=0;i<n;i++)for(let j=0;j<n;j++)w2i+=Aij*vj;lam=v.reduce((s,x,i)=>s+x*w2i,0)}eigs.push({val:lam,vec:v.map(x=>x.toFixed(6))});for(let i=0;i<n;i++)for(let j=0;j<n;j++)Aij-=lam*vi*vj;if(Math.abs(lam)<EPS)break}let o='<span class="y">特征值 & 特征向量:</span>\n';for(let i=0;i<eigs.length;i++)o+=`λ{i+1}=\{eigsi.val.toFixed(6)}</span> vec: ${eigs\[i.vec.join(', ')}]\n`;$('matResult').innerHTML=o}
function svdJacobi(mat,iters=100){let m=mat.length,n=mat0.length,ATA=Array.from({length:n},(,i)=>Array.from({length:n},(,j)=>{let s=0;for(let k=0;k<m;k++)s+=matki*matkj;return s})),V=Array.from({length:n},(,i)=>Array.from({length:n},(,j)=>i===j?1:0));for(let iter=0;iter<iters;iter++){let max=0,p=0,q=1;for(let i=0;i<n;i++)for(let j=i+1;j<n;j++)if(Math.abs(ATAij)>max){max=Math.abs(ATAij);p=i;q=j}if(max<EPS)break;let theta=0.5*Math.atan2(2*ATApq,ATApp-ATAqq),c=Math.cos(theta),s=Math.sin(theta);let rp=ATAp.slice(),rq=ATAq.slice();for(let j=0;j<n;j++){ATApj=c*rpj-s*rqj;ATAqj=s*rpj+c*rqj}let cp=ATA.map(r=>rp),cq=ATA.map(r=>rq);for(let i=0;i<n;i++){ATAip=c*cpi-s*cqi;ATAiq=s*cpi+c*cqi}let vp=V.map(r=>rp),vq=V.map(r=>rq);for(let i=0;i<n;i++){Vip=c*vpi-s*vqi;Viq=s*vpi+c*vqi}}let sig=\[\];for(let i=0;i<n;i++){let val=Math.sqrt(Math.max(0,ATAii));sig.push({val,vec:V.map(r=>ri)})}sig.sort((a,b)=>b.val-a.val);let U=Array.from({length:m},()=>Array(n).fill(0));for(let j=0;j<n;j++)if(sigj.val>EPS)for(let i=0;i<m;i++){let s=0;for(let k=0;k<n;k++)s+=matik*sigj.veck;Uij=s/sigj.val}return{U,sigma:sig.map(s=>s.val),V}}
function calcSVD(){let m=parseM(('singleMatInput').value);if(!m){('matResult').innerHTML='<span class="r">格式错误</span>';return}let{sigma,U,V}=svdJacobi(m);let o='<span class="y">奇异值:</span>'+sigma.map((s,i)=>`σ{i+1}=\{s.toFixed(6)}</span>`).join(' ')+'\n';o+=`<span class="y">U矩阵:</span>\n{fmtMat(U)}\\n\`;o+=\`\V矩阵:\\\n{fmtMat(V)}`;$('matResult').innerHTML=o}
function matMul(A,B){let n=A.length,C=Array.from({length:n},()=>Array(n).fill(0));for(let i=0;i<n;i++)for(let k=0;k<n;k++)for(let j=0;j<n;j++)Cij+=Aik*Bkj;return C}
function calcMatMul(){let raw=('matInput').value.trim(),blk=raw.split(/\\n\\s\*\\n/);if(blk.length\<2){('matResult').innerHTML='<span class="r">需要两个矩阵</span>';return}let pM=t=>{let rs=t.trim().split('\n').filter(r=>r.trim()).map(r=>r.trim().split(/\s+/).map(Number)),n=rs.length;for(let r of rs)if(r.length!==n||r.some(isNaN))return null;return rs};let A=pM(blk0),B=pM(blk1);if(!A||!B||A.length!==B.length){('matResult').innerHTML='\格式错误或阶数不等\';return}let C=matMul(A,B);('matResult').innerHTML=`<span class="y">A×B:</span>\n${fmtMat(C)}`}
function solveLinear(A,b,trace=false){let n=A.length,aug=A.map((r,i)=>...r,b\[i]),rk=0,st=trace?'开始高斯消元...':null;for(let k=0;k<n;k++){let mr=k;for(let i=k+1;i<n;i++)if(Math.abs(augik)>Math.abs(augmrk))mr=i;if(trace)st.push(`选主元列{k}行{mr}`);aug\[k,augmr]=aug\[mr,augk];if(Math.abs(augkk)<EPS){let az=1;for(let j=0;j<n;j++)if(Math.abs(augkj)>EPS){az=0;break}if(az&&Math.abs(augkn)>EPS){if(trace)st.push('无解');return trace?{state:2,x:null,steps:st.join('\n')}:{state:2,x:null}}continue}rk++;let p=augkk;for(let j=k;j<=n;j++)augkj/=p;if(trace)st.push(`归一化第{k}行\`);for(let i=0;i\
function calcEq(){let raw=('eqInput').value.trim(),rows=raw.split('\\n').filter(r=\>r.trim()).map(r=\>r.trim().split(/\\s+/).map(Number));if(rows.length===0\|\|rows.some(r=\>r.length!==rows\[0\].length)){('eqResult').innerHTML='<span class="r">格式错误</span>';return}let n=rows0.length-1;if(n<1||rows.length!==n){('eqResult').innerHTML='\行列数不匹配\';return}let A=rows.map(r=\>r.slice(0,n)),b=rows.map(r=\>r\[n\]),{state,x}=solveLinear(A,b);let o='';if(state===2)o+='\无解\\\n';else if(state===1)o+='\无穷多解\\\n';else o+='\唯一解\\\n';if(x)for(let i=0;i\
function calcEqSteps(){let raw=('eqInput').value.trim(),rows=raw.split('\\n').filter(r=\>r.trim()).map(r=\>r.trim().split(/\\s+/).map(Number));if(rows.length===0\|\|rows.some(r=\>r.length!==rows\[0\].length)){('eqResult').innerHTML='<span class="r">格式错误</span>';return}let n=rows0.length-1;if(n<1||rows.length!==n){('eqResult').innerHTML='\行列数不匹配\';return}let A=rows.map(r=\>r.slice(0,n)),b=rows.map(r=\>r\[n\]),{state,x,steps}=solveLinear(A,b,true);let o=\`\消元步骤:\\\n{steps}\n\n`;if(state===2)o+='<span class="r">无解</span>\n';else if(state===1)o+='<span class="v">无穷多解</span>\n';else o+='<span class="g">唯一解</span>\n';if(x)for(let i=0;i<n;i++)o+=`x{i+1}=\{xi.toFixed(6)}</span>\n`;$('eqResult').innerHTML=o}
function tokenizeBool(s){let t=\[\],i=0;s=s.replace(/\s+/g,'');while(i<s.length){if(s.substr(i,3)==='<->'){t.push({t:'op',v:'<->'});i+=3}else if(s.substr(i,2)==='->'){t.push({t:'op',v:'->'});i+=2}else if('&|!()'.includes(si))t.push({t:'op',v:si++});else if(si==='1'||si==='0')t.push({t:'bool',v:parseInt(si++)});else if(/a-zA-Z/.test(si)){let n='';while(i<s.length&&/a-zA-Z/.test(si))n+=si++;let l=n.toLowerCase();if(l==='t')t.push({t:'bool',v:1});else if(l==='f')t.push({t:'bool',v:0});else t.push({t:'var',v:n.toUpperCase()})}else i++}return t}
function evalBool(input,vars={}){let tokens=tokenizeBool(input),pos=0;let peek=()=>pos<tokens.length?tokenspos:null,eat=()=>tokenspos++;function primary(){let tk=peek();if(!tk)return 0;if(tk.v==='('){eat();let v=iff();if(peek()&&peek().v===')')eat();return v}if(tk.v==='!'){eat();return 1-primary()}if(tk.t==='bool')return eat().v;if(tk.t==='var')return varseat().v??0;eat();return 0}function and(){let v=primary();while(peek()&&peek().v==='&'){eat();v=v&primary()}return v?1:0}function or(){let v=and();while(peek()&&peek().v==='|'){eat();v=v|and()}return v?1:0}function imp(){let v=or();if(peek()&&peek().v==='->'){eat();v=(!v|imp())?1:0}return v}function iff(){let v=imp();if(peek()&&peek().v==='<->'){eat();v=(v===iff())?1:0}return v}return iff()}
function collectVars(f){let s=new Set(),t=tokenizeBool(f);for(let tk of t)if(tk.t==='var')s.add(tk.v);return Array.from(s).sort()}
function calcLogic(){let f=('logicInput').value.trim(),vars=collectVars(f),o='';if(vars.length===0){let r=evalBool(f,{});o=\`= \{r}</span> <span class="y">({r?'TRUE':'FALSE'})\\`}else{o=\`\{vars.length}变量</span>\n`;o+=vars.map(v=>`<span class="v">{v}\\`).join(' ')+' \| '+f+'\\n';o+='─'.repeat(vars.length\*2+f.length+4)+'\\n';for(let i=0;i\<(1\<\
function calcInfer(){let raw=('inferInput').value.trim(),lines=raw.split('\\n').filter(l=\>l.trim());if(lines.length\<2){('inferResult').innerHTML='<span class="r">至少变量和规则</span>';return}let vp={},vd=lines0.match(/A-Za-z\s*=\s*-?\\d.+(?:eE+-?\d+)?/g);if(vd)for(let d of vd){letn,v=d.split('=').map(s=>s.trim());vpn.toUpperCase()=parseFloat(v)}let rules=\[\];for(let i=1;i<lines.length;i++){let p=linesi.split(',').map(s=>s.trim());if(p.length>=5)rules.push({cond:p0,formula:p1,pri:parseInt(p2)||0,resVar:p3,lock:parseInt(p4)||0})}rules.sort((a,b)=>a.pri-b.pri);let locked=false,o=`<span class="y">初始变量:</span>`;for(letk,vof Object.entries(vp))o+=` <span class="v">{k}\={v}`;o+='\n\n';for(let r of rules){if(locked)break;let cr=evalExpr(r.cond,vp);o+=`<span class="y">规则${r.pri}</span> {r.cond} → \`;if(!isNaN(cr)\&\&Math.abs(cr)\>EPS){let fr=evalExpr(r.formula,vp);if(!isNaN(fr)){o+=\`\{r.formula}={fr}\\\n\`;if(r.resVar!=='-'){vp\[r.resVar.toUpperCase()\]=fr;o+=\`存入 {r.resVar}={fr}\\n\`}if(r.lock){o+='\锁定\\\n';locked=true}}else o+=\`\公式错误\\\n\`}else o+=\`\条件不成立\\\n\`}o+='\\n\最终变量:\';for(let\[k,v\]of Object.entries(vp))o+=\` \{k}</span>={typeof v==='number'?v.toFixed(6):v}\`;('inferResult').innerHTML=o}
function calcODE(){let expr=('odeExpr').value.trim(),x0=parseFloat(('odeX0').value),y0=parseFloat(('odeY0').value),h=parseFloat(('odeH').value),N=parseInt(('odeN').value);if(isNaN(x0)\|\|isNaN(y0)\|\|isNaN(h)\|\|isNaN(N)\|\|h\<=0\|\|N\<1\|\|N\>10000){('odeResult').innerHTML='<span class="r">参数错误</span>';return}let xs=x0,ys=y0;for(let i=0;i<N;i++){let xn=xsi,yn=ysi;let k1=evalExpr(expr,{x:xn,y:yn});let k2=evalExpr(expr,{x:xn+h/2,y:yn+h*k1/2});let k3=evalExpr(expr,{x:xn+h/2,y:yn+h*k2/2});let k4=evalExpr(expr,{x:xn+h,y:yn+h*k3});let ynew=yn+h*(k1+2*k2+2*k3+k4)/6;xs.push(xn+h);ys.push(ynew)}let o=`<span class="y">ODE结果 (RK4, h={h}, N={N}):</span>\n x\t\t y\n`;for(let i=0;i<=N;i+=Math.max(1,Math.floor(N/20)))o+=`{xs\[i\].toFixed(4).padStart(8)} {ysi.toFixed(8).padStart(14)}\n`;$('odeResult').innerHTML=o}
function calcNonlinear(){let expr=('nlExpr').value.trim(),x=parseFloat(('nlX0').value);if(isNaN(x)){('nlResult').innerHTML='\参数错误\';return}for(let i=0;i\<100;i++){let fx=evalExpr(expr,{x}),df=(evalExpr(expr,{x:x+EPS})-fx)/EPS;if(Math.abs(fx)\
function calcBisect(){let expr=('nlExpr').value.trim(),a=parseFloat(('nlA').value),b=parseFloat(('nlB').value);if(isNaN(a)\|\|isNaN(b)\|\|a\>=b){('nlResult').innerHTML='<span class="r">参数错误</span>';return}let fa=evalExpr(expr,{x:a}),fb=evalExpr(expr,{x:b});if(fa*fb>0){('nlResult').innerHTML='\区间内可能无根\';return}for(let i=0;i\<100;i++){let c=(a+b)/2,fc=evalExpr(expr,{x:c});if(Math.abs(fc)\
function calcIntEq(){let Kexpr=('inteqK').value.trim(),Fexpr=('inteqF').value.trim(),lambda=parseFloat(('inteqLambda').value),a=parseFloat(('inteqA').value),b=parseFloat(('inteqB').value),n=parseInt(('inteqN').value);if(isNaN(lambda)||isNaN(a)||isNaN(b)||isNaN(n)||n<2||n>200){('inteqResult').innerHTML='\参数错误\';return}let h=(b-a)/(n-1),xs=Array.from({length:n},(_,i)=\>a+i\*h),f=xs.map(x=\>evalExpr(Fexpr,{x})),A=Array.from({length:n},()=\>Array(n).fill(0));for(let i=0;i\
function calcPDE(){let type=('pdeType').value,param=parseFloat(('pdeParam').value),L=parseFloat(('pdeL').value),T=parseFloat(('pdeT').value),Nx=parseInt(('pdeNx').value),Ny=parseInt(('pdeNy').value),Nt=parseInt(('pdeNt').value),initExpr=('pdeInit').value.trim();if(isNaN(param)||isNaN(L)||isNaN(T)||isNaN(Nx)||isNaN(Ny)||isNaN(Nt)||Nx<2||Ny<2||Nt<1||Nx>100||Ny>100||Nt>5000){$('pdeResult').innerHTML='<span class="r">参数错误(网格≤100,时间步≤5000)</span>';return}let dx=L/(Nx-1),dy=L/(Ny-1),dt=T/Nt;
let size=Nx*Ny;
let gCurr=\[\],gPrev=\[\],gNext=\[\];
for(let i=0;i<size;i++){gCurri=0;gPrevi=0;gNexti=0}
let idx=(i,j)=>i*Ny+j;
for(let i=0;i<Nx;i++)for(let j=0;j<Ny;j++){
let x=i*dx,y=j*dy;
let val=evalExpr(initExpr,{x,y});
gCurridx(i,j)=val;
gPrevidx(i,j)=val;
}
for(let t=0;t<Nt;t++){
for(let i=1;i<Nx-1;i++){
for(let j=1;j<Ny-1;j++){
let lap=(gCurridx(i+1,j)+gCurridx(i-1,j)+gCurridx(i,j+1)+gCurridx(i,j-1)-4*gCurridx(i,j))/(dx*dx);
if(type==='heat'){
gNextidx(i,j)=gCurridx(i,j)+param*dt*lap;
}else{
if(t===0){
gNextidx(i,j)=gCurridx(i,j)+0.5*param*param*dt*dt*lap;
}else{
gNextidx(i,j)=2*gCurridx(i,j)-gPrevidx(i,j)+param*param*dt*dt*lap;
}
}
}
}
for(let i=0;i<size;i++){gPrevi=gCurri;gCurri=gNexti}
}
let centerVal=gCurridx(Math.floor(Nx/2),Math.floor(Ny/2));
let o=`<span class="y">PDE结果 ({type==='heat'?'热方程':'波动方程'}, {Nx}×{Ny}网格, {Nt}步):</span>\n中心点({(L/2).toFixed(2)},{(L/2).toFixed(2)}) @ t={T}:\{centerVal.toFixed(8)}</span>`;$('pdeResult').innerHTML=o}
// 外层大标签切换
document.querySelectorAll('.wrap > .tabs > .tab').forEach(tab=>{
tab.addEventListener('click',()=>{
document.querySelectorAll('.wrap > .tabs > .tab').forEach(t=>t.classList.remove('active'));
document.querySelectorAll('.panel').forEach(p=>p.classList.remove('active'));
tab.classList.add('active');
$('panel-'+tab.dataset.panel).classList.add('active');
});
});
// 方程求解内部子标签切换
document.querySelectorAll('#panel-eqsolver .inner-tabs .tab').forEach(tab=>{
tab.addEventListener('click',()=>{
document.querySelectorAll('#panel-eqsolver .inner-tabs .tab').forEach(t=>t.classList.remove('active'));
document.querySelectorAll('.subpanel').forEach(sp=>sp.classList.remove('active'));
tab.classList.add('active');
$('sub-'+tab.dataset.sub).classList.add('active');
});
});
</script>
</body>
</html>