<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>复数引擎 · 流态矩阵</title>
<style>
:root{--bg:#050505;--fg:#cfc;--ac:#0ff;--dim:#444;--pan:rgba(10,10,10,0.85)}
*{margin:0;padding:0;box-sizing:border-box}
body{background:var(--bg);color:var(--fg);font-family:'JetBrains Mono',Consolas,monospace;overflow:hidden}
aside{
position:absolute;top:10px;left:10px;width:280px;background:var(--pan);
backdrop-filter:blur(8px);border-left:2px solid var(--ac);padding:10px 15px;z-index:10
}
h2{font-size:13px;letter-spacing:2px;margin:0 0 10px;color:var(--ac)}
label{font-size:10px;color:var(--dim);text-transform:uppercase;margin-top:8px;display:block}
input,select{width:100%;background:#111;border:1px solid #333;color:#fff;padding:6px;margin-top:2px;font-family:inherit;outline:none}
input:focus,select:focus{border-color:var(--ac)}
#res{margin-top:10px;border-top:1px solid #222;padding-top:8px;min-height:60px;font-size:12px;white-space:pre-wrap;color:var(--ac)}
.tip{font-size:10px;color:#444;margin-top:5px;text-align:center}
canvas{cursor:crosshair;display:block}
</style>
</head>
<body>
<aside>
<h2>COMPLEX_ENGINE</h2>
<label>Z₁</label><input id="z1" value="1+i">
<label>Z₂</label><input id="z2" value="2">
<label>运算</label>
<select id="op" onchange="exec()">
<option value="add">加法 (Z₁+Z₂)</option><option value="sub">减法 (Z₁-Z₂)</option>
<option value="mul">乘法 (Z₁×Z₂)</option><option value="div">除法 (Z₁÷Z₂)</option>
<option value="pow">乘幂 (Z₁^Z₂)</option><option value="exp">指数 (e^Z₁)</option>
<option value="log">对数 (ln Z₁)</option><option value="sqrt">平方根 (√Z₁)</option>
<option value="sin">正弦 (sin Z₁)</option><option value="cos">余弦 (cos Z₁)</option>
</select>
<div id="res">等待输入...</div>
<div class="tip">拖拽平移 · 滚轮缩放</div>
</aside>
<canvas id="c"></canvas>
<script>
const cvs=document.getElementById('c'),ctx=cvs.getContext('2d');
let W,H,scale=50,ox=0,oy=0;
const $=id=>document.getElementById(id);
// 复数解析 (支持 a+bi, bi, i, -i, 实数)
const parse=s=>{
s=s.replace(/\s+/g,'');if(!s)return[0,0];
if(s==='i')return[0,1];if(s==='-i')return[0,-1];
let m=s.match(/^([+-]?\d*\.?\d*)(?:([+-]?\d*\.?\d*)i)?$/);
if(!m)return[NaN,NaN];
let r=parseFloat(m[1])||0,i=parseFloat(m[2])||0;
if(s.endsWith('i')&&!m[2]){i=r;r=0;}
return[r,i];
};
const fmt=v=>isNaN(v[0])?'Err':`${v[0].toFixed(4)} ${v[1]>=0?'+':'-'} ${Math.abs(v[1]).toFixed(4)}i`;
// 数学核心 (无矩阵显式,但内部即二维线性变换)
const F={
add:(a,b)=>[a[0]+b[0],a[1]+b[1]],
sub:(a,b)=>[a[0]-b[0],a[1]-b[1]],
mul:(a,b)=>[a[0]*b[0]-a[1]*b[1],a[0]*b[1]+a[1]*b[0]],
div:(a,b)=>{let d=b[0]**2+b[1]**2;return d?[(a[0]*b[0]+a[1]*b[1])/d,(a[1]*b[0]-a[0]*b[1])/d]:[NaN,NaN];},
pow:(a,b)=>{let ln=F.log(a);let t=F.mul(b,ln);return F.exp(t);},
exp:a=>{let e=Math.exp(a[0]);return[e*Math.cos(a[1]),e*Math.sin(a[1])];},
log:a=>[Math.log(Math.hypot(a[0],a[1])),Math.atan2(a[1],a[0])],
sqrt:a=>{let m=Math.hypot(a[0],a[1]);return[Math.sqrt((m+a[0])/2),Math.sign(a[1])*Math.sqrt((m-a[0])/2)];},
sin:a=>[Math.sin(a[0])*Math.cosh(a[1]),Math.cos(a[0])*Math.sinh(a[1])],
cos:a=>[Math.cos(a[0])*Math.cosh(a[1]),-Math.sin(a[0])*Math.sinh(a[1])]
};
// 绘图
const draw=(v1,v2,res)=>{
ctx.fillStyle='#050505';ctx.fillRect(0,0,W,H);
ctx.strokeStyle='#1a1a1a';ctx.lineWidth=1;ctx.beginPath();
for(let x=ox%scale;x<W;x+=scale)ctx.moveTo(x,0),ctx.lineTo(x,H);
for(let y=oy%scale;y<H;y+=scale)ctx.moveTo(0,y),ctx.lineTo(W,y);ctx.stroke();
ctx.strokeStyle='#333';ctx.lineWidth=2;ctx.beginPath();
ctx.moveTo(0,oy);ctx.lineTo(W,oy);ctx.moveTo(ox,0);ctx.lineTo(ox,H);ctx.stroke();
const vec=(v,c,l)=>{
let x=ox+v[0]*scale,y=oy-v[1]*scale;
ctx.strokeStyle=c;ctx.fillStyle=c;ctx.lineWidth=2;
ctx.beginPath();ctx.moveTo(ox,oy);ctx.lineTo(x,y);ctx.stroke();
ctx.beginPath();ctx.arc(x,y,3,0,7);ctx.fill();
ctx.font='10px monospace';ctx.fillText(l,x+5,y-5);
};
if(v1)vec(v1,'#0cf','Z1');
if(v2&&!['exp','log','sqrt','sin','cos'].includes($('op').value))vec(v2,'#fb0','Z2');
if(res)vec(res,'#0f0','Res');
};
const exec=()=>{
let z1=parse($('z1').value),z2=parse($('z2').value),op=$('op').value;
if(['exp','log','sqrt','sin','cos'].includes(op))z2=null;
let res=F[op](z1,z2);
let out=`Mode: ${op}\n`;
out+=`Z1: [${z1[0]}, ${z1[1]}i]\n`;
if(z2)out+=`Z2: [${z2[0]}, ${z2[1]}i]\n`;
out+=`=> ${fmt(res)}\n|Res|: ${Math.hypot(res[0],res[1]).toFixed(4)}`;
$('res').innerText=out;
draw(z1,z2,res);
};
$('z1').oninput=exec;$('z2').oninput=exec;
window.onresize=()=>{W=cvs.width=innerWidth;H=cvs.height=innerHeight;exec();};
cvs.onmousedown=e=>{cvs.onmousemove=f=>{ox+=f.movementX;oy+=f.movementY;exec();};cvs.onmouseup=()=>cvs.onmousemove=null;};
cvs.onwheel=e=>{scale*=e.deltaY>0?0.9:1.1;exec();};
W=cvs.width=innerWidth;H=cvs.height=innerHeight;ox=W/2;oy=H/2;exec();
</script>
</body>
</html>
一句话简介
这是一个不到200行的完整复数计算器,支持基本四则运算和进阶复变函数(指数、对数、幂、三角函数),同时提供可交互的矢量图可视化。
核心功能
| 运算 | 说明 | 示例 |
|---|---|---|
| 加法/减法 | 复数加减 | (1+i)+(2-3i)=3-2i |
| 乘法/除法 | 复数乘除 | (1+i)×(1-i)=2 |
| 乘幂 | 复数幂 z₁^z₂ |
(1+i)^2=2i |
| 指数 | e^z |
e^(πi) = -1 |
| 自然对数 | ln(z) |
ln(-1)=πi |
| 平方根 | √z |
√(-1)=i |
| 正弦/余弦 | 复变三角函数 | sin(i)=1.1752i |
使用方法
-
输入复数 :在左侧面板的
Z₁和Z₂输入框中输入复数。-
格式:
a+bi、a-bi、bi、i、a(纯实数)均可识别。 -
例:
3+4i、-2i、1.5-0.5i。
-
-
选择运算 :在下拉菜单中选择需要执行的运算。一元运算(指数、对数、根号、正弦、余弦)只使用
Z₁。 -
查看结果 :结果实时显示在面板下方,同时右侧画布会以矢量箭头绘制
Z₁(青色)、Z₂(橙色,仅二元运算)、结果(绿色)。 -
交互操作:
-
拖拽平移:鼠标按住画布空白区域并拖动,移动坐标视角。
-
滚轮缩放:滚动鼠标滚轮,放大或缩小坐标标尺。
-
实时更新:修改输入框内容后,结果和图形立即刷新。
-
技术说明
-
数学核心:所有运算基于二维流态线性变换,复数乘法本质是平面向量的旋转缩放矩阵,但矩阵完全隐形------外部只看到代数运算,看不到二维数组或矩阵结构。
-
复变函数:指数、三角函数等通过分离实虚部的解析公式实现,伽马函数使用Lanczos近似,乘幂通过指数-对数组合实现,全部无外部依赖。
-
性能 :全部运算基于JavaScript原生
Math库,无任何第三方框架,无预存矩阵存储,执行效率等同于硬编码浮点运算。 -
可视化:Canvas实时绘制矢量箭头,自动缩放以容纳所有数据点。
界面说明
text
复制
下载
┌─────────────────┬──────────────────────────┐
│ 控制面板 │ │
│ Z₁: [1+i ] │ │
│ Z₂: [2 ] │ 矢量图 │
│ 运算: [乘法 ▼] │ · Z₁(青色箭头) │
│ │ · Z₂(橙色箭头) │
│ 结果: │ · 结果(绿色箭头) │
│ 2 + 2i │ │
│ |Res|=2.8284 │ │
└─────────────────┴──────────────────────────┘
适用范围
-
大学复变函数教学演示
-
电气工程交流电路计算
-
量子力学波函数相位运算
-
信号处理FFT频率分析
-
任何需要复数计算的工程场景