Node.js通用计算14--洛伦兹吸引子结果展示和KaTex语法
写在前面
转眼间,上一篇博文已经是1年零2个月前的产物了。这一年里,无数次想敲点字,哪怕是一点点,但是始终没有勇气。一是我不想搬运一些我自己都弄不清楚的东西。二是自己的工作离代码很远,平时忙起来没有时间去挖掘写作的方向,三是2025年家里诸事不,所有的事都在扰乱自己的心绪,没法沉下心来思考、提炼、总结。最重要的是这一年里整个社会发生了巨大的变化,人工智能在编程领域广泛应用,尤其是open claw 这类人工智能体,现在一个小学生只要告诉AI需要什么,就能得到一个相对优秀的代码,其所需要的学习成本所花费的时间远远小于笔者这样的书呆子。AI是一个很好的工具,一个为我们人类服务的工具,我们必须学会利用他。
一、 洛伦兹吸方程 Lorenz Equations 及其求解代码
作为一名力学专业研究生,我觉的没有什么比洛伦兹吸引子更容易激发普通人对计算力学的兴趣了,她很美、又很神秘、也很专业,因此首先我们就拿洛伦兹吸引子作为开胃菜。首先要介绍一下Lorenz 方程。洛伦兹方程(Lorenz equations),这是由美国气象学家 爱德华·洛伦兹(Edward N. Lorenz) 于1963年提出的一组非线性常微分方程。这组方程最初用于简化大气对流模型,后来成为混沌理论和奇异吸引子研究的奠基性模型。该方程可以写成:
{ d x d t = σ ( y − x ) d y d t = x ( ρ − z ) − y d z d t = x y − β z \begin{cases} \frac{dx}{dt} = \sigma (y - x) \\ \frac{dy}{dt} = x (\rho - z) - y \\ \frac{dz}{dt} = x y - \beta z \end{cases} ⎩ ⎨ ⎧dtdx=σ(y−x)dtdy=x(ρ−z)−ydtdz=xy−βz
其中 σ和ρ分别代表普朗特数、瑞利数。 β 为几何控制参数。一组典型参数为σ=10 , ρ=28, β=2.6666666。
我们给定初值 (x,y,z)=(1.0,1.0,1.0) ,时间步长给dt=0.001,迭代总时间200。
开始迭代。完整代码如下
//lorenz_rk4.js
import {writeFile} from 'fs/promises'
//lorenz方程求导
function lorenzDerivatives(x, y, z, sigma, rho, beta) {
const dx = sigma * (y - x);
const dy = x * (rho - z) - y;
const dz = x * y - beta * z;
return [dx, dy, dz];
}
//4步龙哥库塔迭代
function rk4Step(x, y, z, dt, sigma, rho, beta) {
const [k1x, k1y, k1z] = lorenzDerivatives(x, y, z, sigma, rho, beta);
const [k2x, k2y, k2z] = lorenzDerivatives(
x + 0.5 * dt * k1x,
y + 0.5 * dt * k1y,
z + 0.5 * dt * k1z,
sigma, rho, beta
);
const [k3x, k3y, k3z] = lorenzDerivatives(
x + 0.5 * dt * k2x,
y + 0.5 * dt * k2y,
z + 0.5 * dt * k2z,
sigma, rho, beta
);
const [k4x, k4y, k4z] = lorenzDerivatives(
x + dt * k3x,
y + dt * k3y,
z + dt * k3z,
sigma, rho, beta
);
const xNext = x + (dt / 6) * (k1x + 2*k2x + 2*k3x + k4x);
const yNext = y + (dt / 6) * (k1y + 2*k2y + 2*k3y + k4y);
const zNext = z + (dt / 6) * (k1z + 2*k2z + 2*k3z + k4z);
return [xNext, yNext, zNext];
}
//求解结果用CSV格式表示
function solveLorenzRK4ToCSV({
sigma = 10,
rho = 28,
beta = 8 / 3,
initialState = [1.0, 1.0, 1.0],
dt = 0.001,
totalTime = 200,
saveEvery = 5
}) {
let [x, y, z] = initialState;
const steps = Math.floor(totalTime / dt);
const lines = ['t,x,y,z']; // CSV header
for (let i = 0; i <= steps; i++) {
const t = i * dt;
if (i % saveEvery === 0) {
// 保留足够精度,避免科学计数法
const row = [
t.toFixed(6),
x.toPrecision(10),
y.toPrecision(10),
z.toPrecision(10)
].join(',');
lines.push(row);
}
[x, y, z] = rk4Step(x, y, z, dt, sigma, rho, beta);
}
return lines.join('\n');
}
//主函数
async function main() {
console.log('正在生成 Lorenz 方程 RK4 结果 (CSV格式)...');
const csvContent = solveLorenzRK4ToCSV();
await writeFile('lorenz_rk4_output.csv', csvContent);
console.log(`已保存到 lorenz_rk4_output.csv`);
console.log(`数据点数量: ${csvContent.split('\n').length - 1}`); // 减去 header
// 预览前几行
const preview = csvContent.split('\n').slice(0, 10).join('\n');
console.log('\n前 10 行预览:\n' + preview);
}
main()
输出结果为:
PS C:\Users\fff96\progarm\blog\lorenz> node.exe lorenz_rk4.js
正在生成 Lorenz 方程 RK4 结果 (CSV格式)...
已保存到 lorenz_rk4_output.csv
数据点数量: 4001
前 10 行预览:
t,x,y,z
0.000000,1.000000000,1.000000000,1.000000000
0.050000,1.287557057,2.400154464,0.9638060638
0.100000,2.133106543,4.471410648,1.113898918
0.150000,3.736715794,7.964065219,1.817756522
0.200000,6.542513104,13.73114882,4.180191224
0.250000,11.04282287,21.77535826,11.01674104
0.300000,16.68476348,27.18347314,26.20629733
0.350000,19.55504068,18.60067371,43.99569238
0.400000,15.36649854,1.113757572,46.75801525
二、匹配ECharts数据集
数据结果显示是科学研究中的重要环节,笔者十五年前还在学校时,数据展示主要用tecplot、paraview、matlab等软件,当然也有大神使用python的matplotib,更有甚者使用excel也能给出一定的展示效果,然而这些方法均需要在电脑上安装特定软件,没有安装便无法查看可视化结果,笔者写这一系列的根本目的是实现只要有浏览器地方就能可视化数据,因此选择了使用ECharts网页服页服务器展示结果。ECharts官方介绍见这里 为了展示需要,我们要对数据结果的格式进行改写,本文选用dimensions + source的形式作为ECharts表格Dataset的数据来源。其基本格式为
{
dataset:{
dimensions: ['t', 'x', 'y', 'z'],
source: [
[0.000000, 1.0000000, 1.0000000, 1.0000000],
[0.050000, 0.95071234, 0.95234567, 1.0012345],
[0.100000, 0.90234567, 0.90789012, 1.0045678],
// ... 更多行
]
}
}
因此我们要对前面代码进行以下修改
// ...(包含 rk4Step 和 lorenzDerivatives 函数,略)
//lorenz_rk4_echarts.js
import {writeFile} from 'fs/promises'
//lorenz方程求导
function lorenzDerivatives(x, y, z, sigma, rho, beta) {
const dx = sigma * (y - x);
const dy = x * (rho - z) - y;
const dz = x * y - beta * z;
return [dx, dy, dz];
}
//4步龙哥库塔迭代
function rk4Step(x, y, z, dt, sigma, rho, beta) {
const [k1x, k1y, k1z] = lorenzDerivatives(x, y, z, sigma, rho, beta);
const [k2x, k2y, k2z] = lorenzDerivatives(
x + 0.5 * dt * k1x,
y + 0.5 * dt * k1y,
z + 0.5 * dt * k1z,
sigma, rho, beta
);
const [k3x, k3y, k3z] = lorenzDerivatives(
x + 0.5 * dt * k2x,
y + 0.5 * dt * k2y,
z + 0.5 * dt * k2z,
sigma, rho, beta
);
const [k4x, k4y, k4z] = lorenzDerivatives(
x + dt * k3x,
y + dt * k3y,
z + dt * k3z,
sigma, rho, beta
);
const xNext = x + (dt / 6) * (k1x + 2*k2x + 2*k3x + k4x);
const yNext = y + (dt / 6) * (k1y + 2*k2y + 2*k3y + k4y);
const zNext = z + (dt / 6) * (k1z + 2*k2z + 2*k3z + k4z);
return [xNext, yNext, zNext];
}
// ...(包含 rk4Step 和 lorenzDerivatives 函数,略)
function generateEChartsDataset() {
const params = {
sigma: 10,
rho: 28,
beta: 8 / 3,
initialState: [1.0, 1.0, 1.0],
dt: 0.001,
totalTime: 200,
saveEvery: 5
};
let [x, y, z] = params.initialState;
const steps = Math.floor(params.totalTime / params.dt);
const source = [];
for (let i = 0; i <= steps; i++) {
if (i % params.saveEvery === 0) {
const t = parseFloat((i * params.dt).toFixed(6));
source.push([
t,
parseFloat(x.toPrecision(8)),
parseFloat(y.toPrecision(8)),
parseFloat(z.toPrecision(8))
]);
}
[x, y, z] = rk4Step(x, y, z, params.dt, params.sigma, params.rho, params.beta);
}
return {
dataset:{
dimensions: ['t', 'x', 'y', 'z'],
source: source
}
};
}
async function main() {
const dataset = generateEChartsDataset();
await writeFile('lorenz_echarts_dataset.json', JSON.stringify(dataset, null, 2));
console.log(`已生成 ECharts dataset,共 ${dataset.dataset.source.length} 个点`);
}
main()
运行后可得到文件 lorenz_echarts_dataset.json
#lorenz_echarts_dataset.json
{
"dataset":{
"dimensions": [ "t", "x", "y", "z" ],
"source": [
[ 0, 1, 1, 1 ],
[ 0.05, 1.2875571, 2.4001545, 0.96380606 ],
[ 0.1, 2.1331065, 4.4714106, 1.1138989 ],
.....
}
三、创建Vue3展示服务
为了更好的随时随地的显示表格,我们这里使用Vue3作为前端框架。
使用下列代码生成一个空白Vue3项目。
pnpm create vue@^3 dataview
其中 data-view是自己创建的项目名称。
进行一些设置后(取消Typescript支持,创建一个空项目,其他选默认 ),我们得到了一个空的vue3项目dataview,进入目录运行命令
pnpm install
安装必要的包,然后得到了 其文件结构如下:
安装依赖
pnpm add echarts echarts-gl naive-ui
下面我们修改App.vue 给他添加一个上传按钮和一个echarts图标框使其能够选择结果文件并显示
<!-- App.vue -->
<template>
<n-config-provider :theme="darkTheme">
<n-space vertical :size="24" style="padding: 24px; max-width: 1200px; margin: 0 auto;">
<h2 style="text-align: center; margin: 0;">Lorenz吸引子轨迹展示</h2>
<n-upload
:show-file-list="false"
:custom-request="handleUpload"
accept=".json"
:max="1"
>
<n-button type="primary">选择轨迹 JSON 文件</n-button>
</n-upload>
<n-alert v-if="error" type="error" closable @close="error = ''">
{{ error }}
</n-alert>
<!-- 图表容器:使用 ref -->
<div ref="chartRef" style="width: 100%; height: 600px; background: #0f0f0f; border-radius: 8px;"></div>
</n-space>
</n-config-provider>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { darkTheme } from 'naive-ui'
import * as echarts from 'echarts'
import 'echarts-gl'
// refs
const chartRef = ref(null)
const error = ref('')
// ECharts 实例
let myChart = null
// 初始化图表
function initChart() {
if (!chartRef.value) return
if (myChart) myChart.dispose()
myChart = echarts.init(chartRef.value)
}
// 组件挂载后初始化
onMounted(() => {
initChart()
window.addEventListener('resize', () => myChart?.resize())
})
// 处理文件上传
async function handleUpload({ file, onFinish, onError }) {
try {
// 确保图表已初始化
if (!myChart) {
initChart()
}
if (!myChart) {
throw new Error('图表容器未就绪')
}
// 读取文件
const text = await readFileAsText(file.file)
const json = JSON.parse(text)
// 校验结构
if (!json?.dataset) {
throw new Error('JSON 必须包含顶层 "dataset" 字段')
}
const { dimensions, source } = json.dataset
if (!Array.isArray(dimensions) || !Array.isArray(source)) {
throw new Error('dataset.dimensions 和 dataset.source 必须是数组')
}
if (dimensions.length < 4) {
throw new Error(`需要至少 4 列(t,x,y,z),当前只有 ${dimensions.length} 列`)
}
if (source.length === 0) {
throw new Error('数据为空')
}
// 构建 3D 轨迹数据
const points = source.map(row => [row[1], row[2], row[3]]) // x, y, z
const times = source.map(row => row[0]) // t
const minT = Math.min(...times)
const maxT = Math.max(...times)
const option = {
tooltip: {
formatter: (params) => {
const [x, y, z, t] = params.value
return `
时间 t: ${t.toFixed(3)}<br/>
位置: (${x.toFixed(2)}, ${y.toFixed(2)}, ${z.toFixed(2)})
`
}
},
visualMap: {
show: true,
dimension: 3,
min: minT,
max: maxT,
inRange: {
color: ['#313695', '#4575b4', '#74add1', '#abd9e9', '#e0f3f8', '#ffffbf', '#fee090', '#fdae61', '#f46d43', '#d73027']
},
bottom: 20,
left: 20,
orient: 'horizontal'
},
grid3D: {
viewControl: {
alpha: 30,
beta: 45,
distance: 200,
panSensitivity: 2
}
},
xAxis3D: { type: 'value', name: 'x' },
yAxis3D: { type: 'value', name: 'y' },
zAxis3D: { type: 'value', name: 'z' },
series: [{
type: 'line3D',
data: points.map((p, i) => [...p, times[i]]),
lineStyle: { width: 3 },
blendMode: 'lighter'
}]
}
myChart.setOption(option, true)
error.value = ''
onFinish()
} catch (err) {
console.error('加载失败:', err)
error.value = err.message || '未知错误'
onError(err)
}
}
// 工具函数:读取文件为文本
function readFileAsText(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader()
reader.onload = () => resolve(reader.result)
reader.onerror = () => reject(new Error('文件读取失败'))
reader.readAsText(file)
})
}
</script>
修改main.js
// main.js
// main.js
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
import naive from 'naive-ui'
app.use(naive)
app.mount('#app')
运行项目
pnpm run dev
浏览器访问 http://localhost:5173/ ,可以看出结果成功显示
四、数据动态显示
为了更加直观的展示Lorenz吸引子非线性动力学特征,我们还可以在时间序列上把运动轨迹显示出来。
<!--App.vue-->
<template>
<n-config-provider :theme="darkTheme">
<n-space vertical :size="24" style="padding: 24px; max-width: 1200px; margin: 0 auto;">
<!-- 标题 -->
<h2 style="text-align: center; margin: 0;">Lorenz 吸引子动态轨迹</h2>
<!-- 文件上传 -->
<n-upload
:show-file-list="false"
:custom-request="handleUpload"
accept=".json"
:max="1"
>
<n-button type="primary">选择轨迹 JSON 文件</n-button>
</n-upload>
<!-- 控制面板 -->
<div v-if="hasData" style="display: flex; align-items: center; gap: 12px; flex-wrap: wrap;">
<n-button @click="play" :disabled="isPlaying">▶ 播放</n-button>
<n-button @click="pause" :disabled="!isPlaying">⏸ 暂停</n-button>
<n-button @click="reset">⏹ 重置</n-button>
<div style="display: flex; align-items: center; gap: 8px; margin-left: 12px;">
<span>速度:</span>
<n-slider
v-model:value="speed"
:min="20"
:max="400"
:step="10"
style="width: 400px;"
/>
<span>{{ speed }} 点/每秒</span>
</div>
</div>
<!-- 错误提示 -->
<n-alert v-if="error" type="error" closable @close="() => error = ''">
{{ error }}
</n-alert>
<!-- 3D 图表容器 -->
<div ref="chartRef" style="width: 100%; height: 600px; background: #0f0f0f; border-radius: 8px;"></div>
</n-space>
</n-config-provider>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import { darkTheme } from 'naive-ui'
import * as echarts from 'echarts'
import 'echarts-gl' // 必须引入以支持 3D
// refs
const chartRef = ref(null)
const error = ref('')
const hasData = ref(false)
// 播放控制
const isPlaying = ref(false)
const speed = ref(200) // ms per point
let timer = null
// 数据
let fullTrajectory = [] // 格式: [[x, y, z, t], ...]
let currentIndex = 0
// ECharts 实例
let myChart = null
// 初始化图表
function initChart() {
if (!chartRef.value) return
if (myChart) myChart.dispose()
myChart = echarts.init(chartRef.value)
}
// 组件挂载
onMounted(() => {
initChart()
window.addEventListener('resize', () => myChart?.resize())
})
// 组件卸载清理
onUnmounted(() => {
if (timer) clearInterval(timer)
myChart?.dispose()
})
// 读取文件为文本
function readFileAsText(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader()
reader.onload = () => resolve(reader.result)
reader.onerror = () => reject(new Error('文件读取失败'))
reader.readAsText(file)
})
}
// 构建 ECharts 3D 配置(关键:包含 coordinateSystem)
function buildChartOption(dataSegment) {
const option = {
tooltip: {},
grid3D: {
viewControl: {
alpha: 30,
beta: 45,
distance: 200,
panSensitivity: 2
}
},
xAxis3D: { type: 'value', name: 'x' },
yAxis3D: { type: 'value', name: 'y' },
zAxis3D: { type: 'value', name: 'z' },
series: [{
type: 'line3D',
coordinateSystem: 'cartesian3D', // ✅ 解决 "xAxis3D '0' not found" 的关键!
data: dataSegment,
lineStyle: { width: 2.5 },
blendMode: 'lighter'
}]
}
// 如果有数据,添加 visualMap(颜色映射时间 t)
if (dataSegment.length > 0) {
const times = dataSegment.map(p => p[3])
const minT = Math.min(...times)
const maxT = Math.max(...times)
option.visualMap = {
show: true,
dimension: 3,
min: minT,
max: maxT,
inRange: {
color: ['#313695', '#4575b4', '#74add1', '#abd9e9', '#e0f3f8', '#ffffbf', '#fee090', '#fdae61', '#f46d43', '#d73027']
},
bottom: 20,
left: 20,
orient: 'horizontal'
}
option.tooltip = {
formatter: (params) => {
const [x, y, z, t] = params.value
return `
时间 t: ${t.toFixed(3)}<br/>
位置: (${x.toFixed(2)}, ${y.toFixed(2)}, ${z.toFixed(2)})
`
}
}
}
return option
}
// 处理文件上传
async function handleUpload({ file, onFinish, onError }) {
try {
if (!myChart) initChart()
if (!myChart) throw new Error('图表容器未就绪')
const text = await readFileAsText(file.file)
const json = JSON.parse(text)
if (!json?.dataset) throw new Error('JSON 必须包含 "dataset" 字段')
const { dimensions, source } = json.dataset
if (!Array.isArray(dimensions) || !Array.isArray(source)) {
throw new Error('dataset.dimensions 和 dataset.source 必须是数组')
}
if (dimensions.length < 4) {
throw new Error(`需要至少 4 列(t,x,y,z),当前只有 ${dimensions.length} 列`)
}
if (source.length === 0) {
throw new Error('数据为空')
}
// 转换为 [[x, y, z, t], ...]
fullTrajectory = source.map(row => [row[1], row[2], row[3], row[0]])
hasData.value = true
reset()
onFinish()
} catch (err) {
console.error(err)
error.value = err.message || '未知错误'
onError(err)
}
}
// 播放动画
function play() {
if (isPlaying.value || currentIndex >= fullTrajectory.length) return
isPlaying.value = true
timer = setInterval(() => {
if (currentIndex >= fullTrajectory.length) {
pause()
return
}
const segment = fullTrajectory.slice(0, currentIndex + 1)
myChart.setOption(buildChartOption(segment), true)
currentIndex++
}, Math.floor(1000/speed.value))
}
// 暂停
function pause() {
if (timer) clearInterval(timer)
timer = null
isPlaying.value = false
}
// 重置
function reset() {
pause()
currentIndex = 0
myChart.setOption(buildChartOption([]), true)
}
</script>
结果大致为:
屏幕录制 2026-03-17 164207
五、用KaTex显示公式
为了能够方便的展示求解的公式,我们需要用到KaTex库。KaTeX 是一个用于在网页中渲染数学公式的 JavaScript 库,由 KaTeX 官方团队 开发。它支持 LaTeX 语法,能够快速、高效地将数学公式渲染为高质量的 HTML/CSS 渲染结果。与 MathJax 相比,KaTeX 更轻量、渲染速度更快,但对某些复杂公式的支持可能稍逊一筹。
主要特点:
1.支持 LaTeX 数学语法(如 E = m c 2 E = mc^2 E=mc2)。
2.渲染速度快,适合需要高性能的场景。
3.提供丰富的数学符号和公式布局。
4.支持自定义字体和样式。
下面给一个KaTex在Vue3中的示例:
<template>
<div class="container">
<h2 style="text-align: center;">Lorenz 方程组</h2>
<div v-html="lorenzHtml" class="math-block"></div>
</div>
</template>
<script setup>
import { computed } from 'vue'
import katex from 'katex'
import 'katex/dist/katex.min.css'
// 定义 Lorenz 方程组的 LaTeX 字符串
const lorenzLatex = String.raw`
\begin{aligned}
&\frac{dx}{dt} = \sigma (y - x) \\
&\frac{dy}{dt} = x (\rho - z) - y \\
&\frac{dz}{dt} = x y - \beta z
\end{aligned}
`
// 使用 KaTeX 渲染为 HTML
const lorenzHtml = computed(() => {
try {
return katex.renderToString(lorenzLatex, {
displayMode: true, // 行间公式(居中显示)
throwOnError: false,
errorColor: '#ff0000'
})
} catch (err) {
console.error('KaTeX 渲染错误:', err)
return '公式渲染失败'
}
})
</script>
<style scoped>
.container {
padding: 20px;
font-family: Arial, sans-serif;
}
.math-block {
margin-top: 1em;
text-align: center;
}
</style>
其结果显示为:
下面给出一些常用KaTex语法
- 希腊字母
| LaTeX 命令 | 符号名称 | LaTeX 命令 | 符号名称 |
|---|---|---|---|
\alpha |
α | \beta |
β |
\gamma |
γ | \delta |
δ |
\epsilon |
ε | \zeta |
ζ |
\eta |
η | \theta |
θ |
\iota |
ι | \kappa |
κ |
\lambda |
λ | \mu |
μ |
\nu |
ν | \xi |
ξ |
\pi |
π | \rho |
ρ |
\sigma |
σ | \tau |
τ |
\upsilon |
υ | \phi |
φ |
\chi |
χ | \psi |
ψ |
\omega |
ω |
| LaTeX 命令 | 符号名称 | LaTeX 命令 | 符号名称 |
|---|---|---|---|
\Alpha |
Α | \Beta |
Β |
\Gamma |
Γ | \Delta |
Δ |
\Epsilon |
Ε | \Zeta |
Ζ |
\Eta |
Η | \Theta |
Θ |
\Iota |
Ι | \Kappa |
Κ |
\Lambda |
Λ | \Mu |
Μ |
\Nu |
Ν | \Xi |
Ξ |
\Pi |
Π | \Rho |
Ρ |
\Sigma |
Σ | \Tau |
Τ |
\Upsilon |
Υ | \Phi |
Φ |
\Chi |
Χ | \Psi |
Ψ |
\Omega |
Ω |
- 数学符号
| LaTeX 命令 | 符号名称 | LaTeX 命令 | 符号名称 |
|---|---|---|---|
+ |
+ | - |
- |
\times |
× | \div |
÷ |
\pm |
± | \mp |
∓ |
\cdot |
· | \ast |
* |
\cup |
∪ | \cap |
∩ |
\subset |
⊂ | \supset |
⊃ |
\subseteq |
⊆ | \supseteq |
⊇ |
= |
= | \neq |
≠ |
\approx |
≈ | \equiv |
≡ |
\leq |
≤ | \geq |
≥ |
\ll |
≪ | \gg |
≫ |
\in |
∈ | \notin |
∉ |
\subset |
⊂ | \supset |
⊃ |
\infty |
∞ | \quad |
空格 |
\partial |
∂ | \nabla |
∇ |
\angle |
∠ | \triangle |
△ |
3.数学结构
分数: \frac{a}{b} \quad \tfrac{a}{b} \quad \dfrac{a}{b}
a b a b a b \frac{a}{b} \quad \tfrac{a}{b} \quad \dfrac{a}{b} bababa
根号: \sqrt{a} \quad \sqrt[n]{a} \quad \sqrt{a + b}
a a n a + b \sqrt{a} \quad \sqrt[n]{a} \quad \sqrt{a + b} anaa+b
积分:\int_a^b f(x) \, dx \quad \sum_{i=1}^n x_i \quad \prod_{i=1}^n x_i
∫ a b f ( x ) d x ∑ i = 1 n x i ∏ i = 1 n x i \int_a^b f(x) \, dx \quad \sum_{i=1}^n x_i \quad \prod_{i=1}^n x_i ∫abf(x)dxi=1∑nxii=1∏nxi
极限: \lim_{x \to 0} f(x) \quad \limsup_{x \to 0} f(x) \quad \liminf_{x \to 0} f(x)
lim x → 0 f ( x ) lim sup x → 0 f ( x ) lim inf x → 0 f ( x ) \lim_{x \to 0} f(x) \quad \limsup_{x \to 0} f(x) \quad \liminf_{x \to 0} f(x) x→0limf(x)x→0limsupf(x)x→0liminff(x)
对齐: \begin{align} a &= b + c \\ d &= e + f \end{align}
a = b + c d = e + f \begin{align} a &= b + c \\ d &= e + f \end{align} ad=b+c=e+f
六、总结
写到这里,我们基本上完成一次科学计算从建模、离散化、代码、数据可视化的全过程。本文中前端大量代码都是由QWen3大模型给出的,虽然中间有少许勘误,需要手动修改,但是整个框架给出来极大减轻了笔者负担,在这里十分感谢阿里巴巴给了这么好的一个免费工具,如果没有QWen3很难想象这篇文章所需要的技术栈笔者一个人要学多久。如果精力允许,我后面会补一篇文章,详细记录本地大语言模型搭建过程。本文到此结束,谢谢各位看官。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐
所有评论(0)