实用工具函数
TianYuan 提供了一系列实用工具函数,涵盖输入输出、类型转换、工作空间管理、方程求解等功能。这些函数让编程更加便捷高效。
输入输出函数
disp - 显示变量
| 语法 |
说明 |
disp(x) |
显示变量 x 的值 |
disp(str) |
显示字符串 |
参数说明
x: 标量、矩阵或字符串
- 矩阵会以格式化的形式显示
- 不返回值,只输出到控制台
示例
# 显示标量
x = 3.14159
disp(x)
# 显示字符串
disp('Hello, TianYuan!')
# 显示矩阵
A = [1 2 3; 4 5 6]
disp('矩阵 A:')
disp(A)
# 显示计算结果
result = sqrt(2)
disp('sqrt(2) = ')
disp(result)
# 在循环中使用
for i = 1:5
disp(['迭代 ', num2str(i)])
end
# 显示向量
v = [1, 2, 3, 4, 5]
disp('向量:')
disp(v)
# 调试输出
x = 10
y = 20
sum_xy = x + y
disp(['x = ', num2str(x), ', y = ', num2str(y)])
disp(['x + y = ', num2str(sum_xy)])
fprintf - 格式化输出
| 语法 |
说明 |
fprintf(format, ...) |
按照格式字符串输出数据 |
格式说明符
%d 或 %i: 整数
%f: 浮点数(默认6位小数)
%.2f: 浮点数(指定小数位数)
%e: 科学计数法
%s: 字符串
\n: 换行符
\t: 制表符
示例
# 基本格式化输出
x = 42
fprintf('x 的值是 %d\n', x)
# 浮点数格式化
pi_val = 3.14159265
fprintf('π ≈ %.2f\n', pi_val) # 保留2位小数
fprintf('π ≈ %.5f\n', pi_val) # 保留5位小数
# 科学计数法
large_num = 1.23e10
fprintf('大数: %e\n', large_num)
# 多个参数
x = 10
y = 20
fprintf('x = %d, y = %d, x + y = %d\n', x, y, x + y)
# 表格输出
fprintf('编号\t姓名\t\t分数\n')
fprintf('1\t张三\t\t85.5\n')
fprintf('2\t李四\t\t92.0\n')
fprintf('3\t王五\t\t78.5\n')
# 循环中的格式化输出
for i = 1:5
square = i^2
cube = i^3
fprintf('%d 的平方是 %d,立方是 %d\n', i, square, cube)
end
# 精度控制
value = 1/3
fprintf('默认精度: %f\n', value)
fprintf('2位小数: %.2f\n', value)
fprintf('10位小数: %.10f\n', value)
类型转换函数
double - 转换为双精度
| 语法 |
说明 |
double(x) |
将 x 转换为双精度浮点数 |
示例
# 确保是双精度类型
x = 42
y = double(x)
disp(y)
# 矩阵转换
A = [1, 2, 3; 4, 5, 6]
B = double(A)
disp(B)
# 注意:TianYuan 中所有数值默认都是 double 类型
# 此函数主要用于显式类型转换和兼容性
num2str - 数值转字符串
| 语法 |
说明 |
num2str(x) |
将数值转换为字符串 |
num2str(x, precision) |
指定精度的数值转字符串 |
示例
# 基本转换
x = 42
s = num2str(x)
disp(['字符串: ', s])
# 浮点数转换
pi_val = 3.14159
s_pi = num2str(pi_val)
disp(['π = ', s_pi])
# 字符串拼接
a = 10
b = 20
message = ['a = ', num2str(a), ', b = ', num2str(b), ', sum = ', num2str(a + b)]
disp(message)
# 构建动态标题
iteration = 5
title_str = ['迭代次数: ', num2str(iteration)]
disp(title_str)
# 科学计数法的数
large = 1.23e15
s_large = num2str(large)
disp(['大数: ', s_large])
# 构建文件名
file_id = 42
filename = ['data_', num2str(file_id), '.txt']
disp(['文件名: ', filename])
字符串操作函数
| 函数 | 说明 |
strcat(s1, s2, ...) | 连接字符串 |
strtrim(s) | 去除首尾空白字符 |
upper(s) | 转大写 |
lower(s) | 转小写 |
strcmp(s1, s2) | 字符串比较(大小写敏感),相等返回 1 |
strcmpi(s1, s2) | 字符串比较(忽略大小写) |
strfind(s, pattern) | 返回所有匹配位置的行向量 |
strrep(s, old, new) | 替换所有匹配子串 |
str2num(s) | 字符串转数值 |
str2double(s) | 字符串转浮点数,与 str2num 等价 |
sprintf(fmt, ...) | 格式化字符串,返回字符串(不输出) |
length(s) | 返回字符串长度 |
示例
% strcat - 连接字符串
s = strcat("Hello", ", ", "World") # "Hello, World"
# strtrim - 去除首尾空白
s2 = strtrim(" hello ") # "hello"
# upper / lower - 大小写转换
upper("hello") # "HELLO"
lower("WORLD") # "world"
# strcmp / strcmpi
strcmp("abc", "abc") # 1
strcmp("abc", "ABC") # 0
strcmpi("abc", "ABC") # 1
# strfind - 查找子串位置
positions = strfind("abcabcabc", "bc") # [2 5 8]
# strrep - 替换子串
result = strrep("hello world", "world", "TianYuan") # "hello TianYuan"
# str2num - 字符串转数值
x = str2num("3.14") # 3.14
# sprintf - 格式化为字符串
s = sprintf("x = %d, y = %.2f", 3, 3.14) # "x = 3, y = 3.14"
filename = sprintf("data_%03d.txt", 7) # "data_007.txt"
文件 I/O 函数
TianYuan 支持基本的文件读写操作,API 与 Matlab/C 标准库兼容。
| 函数 | 说明 |
fopen(filename, mode) | 打开文件,返回文件句柄 fid(≥3) |
fclose(fid) | 关闭文件 |
fprintf(fid, fmt, ...) | 格式化写入文件(fid=1 为 stdout) |
fgetl(fid) | 读一行(不含换行符),EOF 返回 -1 |
fgets(fid) | 读一行(含换行符),EOF 返回 -1 |
feof(fid) | 到达文件末尾时返回 1 |
load(filename) | 读取纯文本矩阵文件,返回矩阵 |
save(filename, varname) | 将矩阵变量保存为文本文件 |
fopen 打开模式
"r":只读
"w":只写(覆盖)
"a":追加写
写文件示例
% 写入文本文件
fid = fopen("output.txt", "w")
fprintf(fid, "Hello, File!\n")
fprintf(fid, "x = %d, y = %.4f\n", 42, 3.14)
fclose(fid)
读文件示例
% 逐行读取文件
fid = fopen("input.txt", "r")
while !feof(fid)
line = fgetl(fid)
if line == -1
break
end
disp(line)
end
fclose(fid)
load / save 矩阵文件
% 保存矩阵到文件
A = [1 2 3; 4 5 6; 7 8 9]
save("matrix.txt", "A")
# 从文件读取矩阵(文件中每行空白分隔数字,# 或 % 行为注释)
B = load("matrix.txt")
disp(B)
文件句柄 1 和 2 分别对应 stdout(标准输出)和 stderr(标准错误),无需 fopen。析构时所有未关闭的文件句柄会自动关闭。
工作空间管理
clear - 清除变量
| 语法 |
说明 |
clear() |
清除所有变量 |
clear('varname') |
清除指定变量 |
示例
# 创建一些变量
x = 10
y = 20
z = 30
# 清除单个变量
clear('x')
# 现在 x 未定义,y 和 z 仍存在
# 清除所有变量
clear()
# 现在所有变量都被清除
# 脚本开始时清除变量
clear()
clc()
disp('开始新的计算...')
# 清除大型矩阵释放内存
A = rand(1000, 1000)
# ... 使用 A ...
clear('A')
# A 占用的内存被释放
clc - 清空控制台
示例
# 清空屏幕
clc()
# 通常在脚本开头使用
clear() # 清除变量
clc() # 清空屏幕
disp('程序开始')
# 在循环中定期清屏
for i = 1:10
if mod(i, 5) == 0
clc()
disp(['已完成 ', num2str(i), ' 次迭代'])
end
end
方程求解函数
roots - 多项式求根
参数说明
p: 多项式系数向量,从高次到低次
- 例如: [1, -3, 2] 表示 x² - 3x + 2
- 返回值: 包含所有根的向量
示例
# 求解二次方程 x^2 - 5x + 6 = 0
# (x - 2)(x - 3) = 0
p = [1, -5, 6]
r = roots(p)
disp('方程的根:')
disp(r) # [2, 3]
# 三次方程 x^3 - 6x^2 + 11x - 6 = 0
# (x-1)(x-2)(x-3) = 0
p = [1, -6, 11, -6]
r = roots(p)
disp('三次方程的根:')
disp(r) # [1, 2, 3]
# 验证根
p = [1, 0, -1] # x^2 - 1 = 0
r = roots(p)
disp('x^2 - 1 = 0 的根:')
disp(r) # [-1, 1]
# 高次多项式
# x^4 - 10x^2 + 9 = 0
p = [1, 0, -10, 0, 9]
r = roots(p)
disp('x^4 - 10x^2 + 9 = 0 的根:')
disp(r)
# 应用:找临界点
# 已知 f(x) = x^3 - 3x^2 + 2
# f'(x) = 3x^2 - 6x = 0
df = [3, -6, 0]
critical_points = roots(df)
disp('临界点:')
disp(critical_points)
solve - 符号方程求解
限制:TianYuan 目前仅支持数值求解,不支持符号计算。
syms 仅用于声明变量名,solve 仅支持一次和二次多项式方程。
对于其他方程类型,请使用 roots(多项式)或数值迭代方法。
| 语法 |
说明 |
solve(expr, var) |
求解符号方程 |
参数说明
expr: 符号表达式(需要先用 syms 声明变量)
var: 要求解的变量
- 返回值: 方程的解
示例
# 声明符号变量
syms('x')
# 求解简单方程 2x + 5 = 0
sol = solve(2*x + 5, x)
disp('2x + 5 = 0 的解:')
disp(sol) # x = -2.5
# 二次方程
syms('x')
sol = solve(x^2 - 4, x)
disp('x^2 - 4 = 0 的解:')
disp(sol)
# 三角方程
syms('x')
sol = solve(sin(x), x)
disp('sin(x) = 0 的解:')
disp(sol)
# 指数方程
syms('x')
sol = solve(exp(x) - 5, x)
disp('e^x - 5 = 0 的解:')
disp(sol)
syms - 声明符号变量
| 语法 |
说明 |
syms('varname') |
声明符号变量 |
示例
# 声明单个符号变量
syms('x')
# 使用符号变量构建表达式
expr = x^2 + 2*x + 1
# 求解
sol = solve(expr, x)
disp(sol)
# 声明多个符号变量
syms('x')
syms('y')
syms('z')
# 符号计算
result = x + y + z
mldivide - 线性系统求解(矩阵左除)
| 语法 |
说明 |
x = mldivide(A, b) |
求解线性方程组 Ax = b |
x = A \ b |
等价的运算符形式 |
参数说明
A: 系数矩阵(m×n)
b: 右侧向量(m×1)
- 返回值: 解向量 x(n×1)
- 比 inv(A)*b 更高效和数值稳定
示例
# 求解线性方程组
# 2x + 3y = 8
# 4x - y = 2
A = [2 3; 4 -1]
b = [8; 2]
x = mldivide(A, b) # 或 x = A \ b
disp('方程组的解:')
disp(x)
# 验证解
result = A * x
disp('验证 Ax:')
disp(result)
disp('应该等于 b:')
disp(b)
# 更大的线性系统
n = 5
A = rand(n, n)
x_true = rand(n, 1)
b = A * x_true # 构造右侧
x_solved = mldivide(A, b)
error = norm(x_solved - x_true)
disp(['求解误差: ', num2str(error)])
# 超定系统(最小二乘解)
# 更多方程than未知数
A = [1 1; 1 2; 1 3] # 3个方程
b = [2; 3; 4] # 2个未知数
x_ls = mldivide(A, b)
disp('最小二乘解:')
disp(x_ls)
# 与直接求逆比较
A = [2 1; 1 3]
b = [5; 8]
x1 = mldivide(A, b) # 推荐方法
x2 = inv(A) * b # 不推荐,效率低且不稳定
disp('mldivide 结果:')
disp(x1)
disp('inv(A)*b 结果:')
disp(x2)
ode45 - 常微分方程求解
| 语法 |
说明 |
ode45(f, tspan, y0) |
使用 Runge-Kutta 方法求解 ODE |
参数说明
f: 函数句柄 dy/dt = f(t, y)
tspan: 时间范围向量 [t0, t1, ..., tn]
y0: 初始条件
- 返回值: [t, y] 时间和解的向量
示例
# 简单的一阶 ODE: dy/dt = -y, y(0) = 1
# 解析解: y = e^(-t)
function dydt = odefun(t, y)
dydt = -y
end
tspan = linspace(0, 5, 50)
y0 = 1
[t, y] = ode45(@odefun, tspan, y0)
# 绘制数值解和解析解
plot(t, y, 'bo-')
hold('on')
y_exact = exp(-t)
plot(t, y_exact, 'r-')
legend(['数值解', '解析解'])
xlabel('时间 t')
ylabel('y(t)')
title('dy/dt = -y 的数值解')
grid('on')
# 指数增长: dy/dt = ky, y(0) = y0
function dydt = growth(t, y)
k = 0.5
dydt = k * y
end
tspan = 0:0.1:10
y0 = 1
[t, y] = ode45(@growth, tspan, y0)
plot(t, y)
xlabel('时间')
ylabel('数量')
title('指数增长模型')
# 简谐振子: d²x/dt² + ω²x = 0
# 转换为一阶系统: dx/dt = v, dv/dt = -ω²x
function dydt = harmonic(t, y)
omega = 2*pi
x = y(1)
v = y(2)
dydt = [v; -omega^2 * x]
end
tspan = linspace(0, 2, 100)
y0 = [1; 0] # x(0) = 1, v(0) = 0
[t, y] = ode45(@harmonic, tspan, y0)
figure(1)
plot(t, y(:, 1)) # 位置 vs 时间
xlabel('时间')
ylabel('位置')
title('简谐振子')
grid('on')
figure(2)
plot(y(:, 1), y(:, 2)) # 相图
xlabel('位置')
ylabel('速度')
title('相空间轨迹')
grid('on')
# Logistic 增长模型: dy/dt = ry(1 - y/K)
function dydt = logistic(t, y)
r = 1.5
K = 100
dydt = r * y * (1 - y / K)
end
tspan = 0:0.1:10
y0 = 10
[t, y] = ode45(@logistic, tspan, y0)
plot(t, y)
xlabel('时间')
ylabel('种群数量')
title('Logistic 增长模型')
grid('on')
# 阻尼振子: d²x/dt² + 2γdx/dt + ω₀²x = 0
function dydt = damped_oscillator(t, y)
gamma = 0.5 # 阻尼系数
omega0 = 2*pi # 固有频率
x = y(1)
v = y(2)
dydt = [v; -2*gamma*v - omega0^2*x]
end
tspan = linspace(0, 5, 200)
y0 = [1; 0]
[t, y] = ode45(@damped_oscillator, tspan, y0)
plot(t, y(:, 1))
xlabel('时间')
ylabel('位移')
title('阻尼振子')
grid('on')
统计与数组操作函数
这些函数提供丰富的向量/矩阵统计运算与数组重排操作,与 MATLAB 语义兼容。
| 函数 | 说明 |
find(A) | 返回 A 中非零元素的线性下标 |
any(A) | 若 A 中任意元素非零则返回 1 |
all(A) | 若 A 中所有元素非零则返回 1 |
prod(A) | 各元素之积(列方向) |
cumsum(A) | 累积和 |
cumprod(A) | 累积积 |
diff(A) | 相邻元素之差 |
var(A) | 方差(除以 n-1) |
std(A) | 标准差(除以 n-1) |
median(A) | 中位数 |
mode(A) | 众数(出现频率最高的值) |
cov(A) | 协方差矩阵 |
corrcoef(A) | 相关系数矩阵 |
repmat(A, m, n) | 将 A 重复排列为 m×n 块 |
repelem(A, n) | 将每个元素重复 n 次 |
cat(dim, A, B) | 沿指定维度拼接数组 |
kron(A, B) | Kronecker 积 |
triu(A) | 上三角部分 |
tril(A) | 下三角部分 |
circshift(A, n) | 循环移位 |
sub2ind(sz, r, c) | 下标转线性索引 |
ind2sub(sz, idx) | 线性索引转下标 |
unique(A) | 返回唯一元素(已排序) |
ismember(a, B) | 判断 a 的元素是否属于 B |
intersect(A, B) | 交集 |
union(A, B) | 并集 |
setdiff(A, B) | 差集(A 中有但 B 中没有) |
示例
v = [3 1 4 1 5 9 2 6]
disp(find(v > 4)) # 非零位置: [5 6 8]
disp(cumsum(v)) # 累积和
disp(var(v)) # 方差
disp(median(v)) # 中位数: 3.5
disp(unique(v)) # 去重排序: [1 2 3 4 5 6 9]
A = [1 2; 3 4]
disp(repmat(A, 1, 2)) # 横向重复: [1 2 1 2; 3 4 3 4]
disp(triu(A)) # 上三角: [1 2; 0 4]
disp(circshift(v, 2)) # 向右循环移 2 位
Cell 与数值转换函数
这些函数用于在 Cell 数组与数值矩阵之间转换,以及对 Cell/数组逐元素应用函数。
| 函数 | 说明 |
cellfun(f, C) | 对 Cell 数组 C 的每个元素应用函数 f,返回数值数组 |
arrayfun(f, A) | 对数值数组 A 的每个元素应用函数 f |
cell2mat(C) | 将同类 Cell 数组转为数值矩阵 |
num2cell(A) | 将数值矩阵转为 Cell 数组 |
示例
C = {1, 4, 9, 16}
lens = cellfun(@sqrt, C) # [1 2 3 4]
A = [1 2 3 4]
B = arrayfun(@(x) x^2 + 1, A) # [2 5 10 17]
M = cell2mat({[1 2]; [3 4]}) # 2×2 矩阵
NC = num2cell([10 20; 30 40]) # 2×2 Cell 数组
高级字符串函数
以下函数在基础字符串操作之上提供分割/拼接、模式匹配、格式解析等能力。
| 函数 | 说明 |
strsplit(s) | 按空白拆分字符串,返回 Cell 数组 |
strsplit(s, d) | 按分隔符 d 拆分字符串 |
strjoin(C) | 用空格将 Cell 字符串数组合并 |
strjoin(C, d) | 用分隔符 d 合并 Cell 字符串数组 |
contains(s, p) | 判断 s 是否包含子串 p,返回 0/1 |
startsWith(s, p) | 判断 s 是否以 p 开头 |
endsWith(s, p) | 判断 s 是否以 p 结尾 |
regexp(s, pat) | 正则匹配,返回首个匹配起始位置 |
regexprep(s, pat, rep) | 正则替换 |
sscanf(s, fmt) | 按格式解析字符串,返回数值向量 |
int2str(x) | 数值取整后转字符串 |
char(n) | 将 ASCII 码转为字符 |
erase(s, p) | 删除 s 中所有 p 出现 |
pad(s, n) | 用空格将字符串填充到长度 n |
示例
parts = strsplit('a,b,c', ',') # {'a','b','c'}
s = strjoin(parts, '-') # 'a-b-c'
disp(contains('hello world', 'world')) # 1
disp(startsWith('TianYuan', 'Tian')) # 1
m = regexp('abc123def', '\d+') # 4 (第一个数字起始位置)
s2 = regexprep('foo BAR foo', 'foo', 'baz') # 'baz BAR baz'
vals = sscanf('3.14 2.71', '%f') # [3.14; 2.71]
disp(char(65)) # 'A'
disp(erase('hello world', 'o')) # 'hell wrld'
高级矩阵函数
这些函数提供广义逆、矩阵函数(指数/对数/平方根)等高级线性代数运算。
| 函数 | 说明 |
pinv(A) | Moore-Penrose 伪逆 |
null(A) | 零空间的正交基(列向量) |
orth(A) | 列空间的正交基 |
lsqminnorm(A, b) | 最小范数最小二乘解 |
expm(A) | 矩阵指数 e^A |
logm(A) | 矩阵对数 |
sqrtm(A) | 矩阵平方根(满足 X*X = A) |
示例
A = [1 2; 3 4; 5 6]
P = pinv(A) # 3×2 矩阵的伪逆 (2×3)
x = P * [1; 2; 3] # 最小范数解
B = [1 0; 0 2]
disp(expm(B)) # diag([e^1, e^2])
disp(sqrtm(B)) # diag([1, sqrt(2)])
N = null([1 2 3]) # 零空间基
多项式、优化与积分函数
这些函数覆盖多项式拟合与求值、卷积/反卷积、单变量零点与极值搜索、数值积分以及插值。
| 函数 | 说明 |
polyfit(x, y, n) | n 次多项式最小二乘拟合,返回系数向量 |
polyval(p, x) | 计算多项式在 x 处的值 |
polyder(p) | 多项式求导 |
polyint(p) | 多项式求积分(常数项为 0) |
conv(a, b) | 多项式相乘(卷积) |
deconv(a, b) | 多项式相除(反卷积) |
fzero(f, x0) | 求函数 f 在 x0 附近的零点 |
fminbnd(f, a, b) | 在区间 [a,b] 内求函数极小值 |
fminsearch(f, x0) | 无梯度多维极小值(Nelder-Mead) |
integral(f, a, b) | 自适应数值积分 ∫[a,b] f(x) dx |
integral2(f, xa, xb, ya, yb) | 二重数值积分 |
interp1(x, y, xi) | 一维线性插值 |
interp2(X, Y, Z, Xi, Yi) | 二维插值 |
示例
x = 0:0.1:2*pi
y = sin(x) + 0.1*randn(size(x))
p = polyfit(x, y, 5) # 5次拟合
y_fit = polyval(p, x)
root = fzero(@(x) x^3 - x - 2, 1.5) # 约 1.5214
I = integral(@(x) sin(x), 0, pi) # 约 2.0
xi = 0:0.05:2*pi
yi = interp1(x, y, xi) # 插值加密
信号处理与统计分布函数
FFT/IFFT 族函数用于频域分析;统计分布函数提供常用概率分布的 PDF、CDF 与逆 CDF。
| 函数 | 说明 |
fft(x) | 一维快速傅里叶变换 |
ifft(x) | 一维快速傅里叶逆变换 |
fft2(A) | 二维 FFT |
ifft2(A) | 二维 IFFT |
fftshift(x) | 将零频分量移至中心 |
normpdf(x, mu, sigma) | 正态分布概率密度 |
normcdf(x, mu, sigma) | 正态分布累积分布函数 |
norminv(p, mu, sigma) | 正态分布逆 CDF(分位数) |
poisspdf(k, lambda) | 泊松分布 PMF |
poisscdf(k, lambda) | 泊松分布 CDF |
exppdf(x, mu) | 指数分布 PDF |
expcdf(x, mu) | 指数分布 CDF |
unifpdf(x, a, b) | 均匀分布 PDF |
unifcdf(x, a, b) | 均匀分布 CDF |
binopdf(k, n, p) | 二项分布 PMF |
binocdf(k, n, p) | 二项分布 CDF |
示例
# FFT 示例:检测正弦频率
Fs = 1000; t = 0:1/Fs:1-1/Fs
x = sin(2*pi*50*t) + 0.5*sin(2*pi*120*t)
X = fft(x)
f = (0:length(X)-1) * Fs / length(X)
plot(f(1:500), abs(X(1:500)))
xlabel('频率 (Hz)'); title('频谱')
# 统计分布示例
x = -3:0.1:3
y = normpdf(x, 0, 1) # 标准正态 PDF
disp(normcdf(1.96, 0, 1)) # 约 0.975
disp(norminv(0.975, 0, 1)) # 约 1.96
disp(binopdf(3, 10, 0.5)) # P(X=3), X~B(10,0.5)
扩展文件 I/O 函数
在基础 fopen/fclose/fprintf 之外,TianYuan 还支持二进制读写、文件定位以及 CSV/textscan 高级解析。
| 函数 | 说明 |
fseek(fid, off, orig) | 移动文件指针(orig: -1=头, 0=当前, 1=尾) |
ftell(fid) | 返回当前文件指针位置(字节) |
frewind(fid) | 将文件指针移到开头 |
fflush(fid) | 刷新文件缓冲区 |
fread(fid, n) | 读取 n 个字节,返回数值向量 |
fwrite(fid, data) | 将数值向量以字节流写入文件 |
csvread(file) | 读取 CSV 文件为数值矩阵 |
csvread(file, r, c) | 从第 r 行 c 列开始读取(0-based) |
csvwrite(file, M) | 将矩阵 M 写入 CSV 文件 |
textscan(fid, fmt) | 按格式字符串解析文件,返回 Cell 数组 |
textscan(fid, fmt, N) | 最多解析 N 条记录 |
示例
# 写入并读回 CSV
M = [1.0 2.0 3.0; 4.0 5.0 6.0]
csvwrite('data.csv', M)
M2 = csvread('data.csv')
disp(M2)
# 二进制读写
fid = fopen('bin.dat', 'w')
fwrite(fid, [1 2 3 4 5])
fclose(fid)
fid = fopen('bin.dat', 'r')
v = fread(fid, 5)
fclose(fid)
disp(v)
# textscan 解析带标签的文本
fid = fopen('scores.txt', 'r')
C = textscan(fid, '%s %f')
fclose(fid)
names = C{1}
scores = C{2}
系统与环境函数
这些函数用于查询工作空间和文件系统状态、获取用户输入以及调用系统命令。
| 函数 | 说明 |
exist(name) | 检查变量/文件是否存在,返回类型码(0=不存在) |
exist(name, type) | 按类型检查('var'、'file' 等) |
dir() | 列出当前目录内容,返回结构体数组 |
dir(path) | 列出指定路径内容 |
input(prompt) | 显示提示并读取用户输入的数值 |
input(prompt, 's') | 读取用户输入的字符串 |
system(cmd) | 执行系统命令,返回退出码 |
[s, out] = system(cmd) | 同时返回退出码和命令输出字符串 |
示例
# 检查变量是否存在
x = 42
if exist('x')
disp('x 存在')
end
# 列出目录
entries = dir('.')
for i = 1:length(entries)
fprintf('%s\n', entries(i).name)
end
# 读取用户输入
n = input('请输入样本数量: ')
name = input('请输入名称: ', 's')
# 执行系统命令
[status, output] = system('date')
fprintf('当前时间: %s\n', output)
计时与调试函数
tic/toc 用于精确计时;assert 和 warning 用于条件检查与调试信息输出。
| 函数 | 说明 |
tic() | 启动计时器 |
toc() | 返回自上次 tic 以来的秒数 |
assert(cond) | 若 cond 为假则抛出错误 |
assert(cond, msg) | 若 cond 为假则以 msg 为错误信息抛出错误 |
assert(A, B, tol) | 断言 A 与 B 的差不超过容差 tol |
warning(msg) | 输出警告信息(不中断执行) |
warning(id, msg) | 输出带标识符的警告信息 |
示例
tic()
A = rand(500, 500)
B = A * A'
elapsed = toc()
fprintf('矩阵乘法耗时: %.4f 秒\n', elapsed)
# 断言测试
x = sqrt(4)
assert(x == 2, 'sqrt(4) 应等于 2')
assert(abs(x - 2) < 1e-10, 'sqrt(4) 数值误差过大')
# 带容差的断言
assert(pi, 3.14159, 1e-4)
# 警告
if elapsed > 1.0
warning('myPkg:slow', '计算耗时超过 1 秒')
end
类型检测函数
class 和 isa 用于在运行时查询变量的数据类型,便于编写通用函数。
| 函数 | 说明 |
class(x) | 返回 x 的类型字符串,如 'double'、'char'、'cell'、'struct' |
isa(x, type) | 若 x 的类型与 type 匹配则返回 1,否则返回 0 |
示例
disp(class(3.14)) # 'double'
disp(class('hello')) # 'char'
disp(class({1,2,3})) # 'cell'
disp(class(struct('a',1))) # 'struct'
disp(isa(42, 'double')) # 1
disp(isa('hi', 'char')) # 1
disp(isa(42, 'char')) # 0
# 在函数中做类型分发
function process(x)
if isa(x, 'char')
fprintf('字符串输入: %s\n', x)
elseif isa(x, 'double')
fprintf('数值输入, 均值=%.4f\n', mean(x))
else
warning('未知类型: %s', class(x))
end
end
动态执行函数
eval 和 feval 允许在运行时动态执行代码字符串或按名称调用函数。
| 函数 | 说明 |
eval(expr) | 将字符串 expr 作为 TianYuan 代码执行 |
eval(expr, catchExpr) | 执行 expr,若出错则执行 catchExpr |
feval(fname, arg1, ...) | 按函数名字符串调用函数,等价于直接调用 |
示例
# eval 动态执行
eval('x = 100')
disp(x) # 100
eval('y = sqrt(x)', 'y = 0') # 若出错则 y=0
disp(y)
# 动态生成变量名
for i = 1:3
eval(['v', num2str(i), ' = i^2'])
end
disp(v1); disp(v2); disp(v3) # 1 4 9
# feval 按名称调用
fname = 'sin'
result = feval(fname, pi/2) # 1.0
disp(result)
# 函数名由参数决定
ops = {'sin', 'cos', 'exp'}
for i = 1:3
y = feval(ops{i}, 1.0)
fprintf('%s(1) = %.4f\n', ops{i}, y)
end
综合应用示例
示例1:数值实验报告生成
# 自动生成实验报告
clc()
clear()
disp('========================================')
disp(' 数值实验报告')
disp('========================================')
disp(' ')
# 实验参数
n = 100
iterations = 50
tolerance = 1e-6
fprintf('实验参数:\n')
fprintf(' 样本数量: %d\n', n)
fprintf(' 迭代次数: %d\n', iterations)
fprintf(' 收敛容差: %.2e\n', tolerance)
disp(' ')
# 生成数据
data = randn(n, 1)
# 统计分析
mean_val = mean(data)
max_val = max(data)
min_val = min(data)
fprintf('统计结果:\n')
fprintf(' 均值: %.4f\n', mean_val)
fprintf(' 最大值: %.4f\n', max_val)
fprintf(' 最小值: %.4f\n', min_val)
disp(' ')
disp('实验完成!')
disp('========================================')
示例2:多项式拟合和评估
# 生成带噪声的数据
x = linspace(0, 10, 50)'
y_true = 2*x.^2 - 3*x + 1
noise = 5 * randn(size(x))
y = y_true + noise
# 使用最小二乘法拟合二次多项式
# y = a*x^2 + b*x + c
X = [x.^2, x, ones(size(x))]
coeffs = mldivide(X, y) # 最小二乘解
a = coeffs(1)
b = coeffs(2)
c = coeffs(3)
fprintf('拟合的多项式: y = %.2fx^2 + %.2fx + %.2f\n', a, b, c)
fprintf('真实的多项式: y = 2.00x^2 - 3.00x + 1.00\n')
# 绘制结果
y_fit = X * coeffs
plot(x, y, 'bo')
hold('on')
plot(x, y_fit, 'r-')
plot(x, y_true, 'g--')
legend(['带噪声数据', '拟合曲线', '真实曲线'])
xlabel('x')
ylabel('y')
title('多项式拟合')
grid('on')
hold('off')
# 计算拟合误差
residuals = y - y_fit
rmse = sqrt(mean(residuals.^2))
fprintf('均方根误差 (RMSE): %.4f\n', rmse)
示例3:交互式数据分析
# 数据分析流程
clear()
clc()
disp('开始数据分析...')
disp(' ')
# 加载数据(模拟)
n_samples = 1000
data = randn(n_samples, 1) * 10 + 50 # 均值50,标准差10
# 描述性统计
disp('描述性统计:')
fprintf(' 样本数量: %d\n', length(data))
fprintf(' 均值: %.2f\n', mean(data))
fprintf(' 最大值: %.2f\n', max(data))
fprintf(' 最小值: %.2f\n', min(data))
disp(' ')
# 异常值检测(简单方法)
mean_val = mean(data)
threshold = 30
outliers = abs(data - mean_val) > threshold
n_outliers = sum(outliers)
fprintf('异常值数量: %d (%.1f%%)\n', n_outliers, n_outliers/n_samples*100)
disp(' ')
# 可视化
figure(1)
plot(1:n_samples, data, 'b.')
xlabel('样本索引')
ylabel('数值')
title(['数据分布 (n = ', num2str(n_samples), ')'])
grid('on')
# 直方图(近似)
figure(2)
n_bins = 20
hist_data = floor((data - min(data)) / (max(data) - min(data)) * (n_bins - 1)) + 1
# 简化的直方图显示
disp('数据分析完成!')
示例4:数值积分验证
# 使用梯形法则计算定积分,与解析解比较
clear()
clc()
disp('数值积分验证')
disp(' ')
# 积分 ∫[0, π] sin(x) dx = 2
a = 0
b = pi
# 不同的步长
step_sizes = [0.1, 0.01, 0.001]
analytical = 2
fprintf('积分: ∫[0, π] sin(x) dx\n')
fprintf('解析解: %.10f\n\n', analytical)
fprintf('步长\t\t数值解\t\t\t误差\n')
fprintf('---------------------------------------------------\n')
for i = 1:length(step_sizes)
h = step_sizes(i)
x = a:h:b
y = sin(x)
# 梯形法则
integral = h * (sum(y) - (y(1) + y(end)) / 2)
error = abs(integral - analytical)
fprintf('%.4f\t\t%.10f\t\t%.2e\n', h, integral, error)
end
示例5:迭代算法进度监控
# 牛顿法求平方根,带进度显示
function y = sqrt_newton(x, tol, max_iter)
# 初始猜测
y = x / 2
disp(['计算 sqrt(', num2str(x), ')'])
disp(' ')
fprintf('迭代\t\t估计值\t\t\t误差\n')
fprintf('---------------------------------------------------\n')
for iter = 1:max_iter
y_new = 0.5 * (y + x / y)
error = abs(y_new - y)
fprintf('%d\t\t%.10f\t\t%.2e\n', iter, y_new, error)
if error < tol
fprintf('\n收敛! 最终结果: %.10f\n', y_new)
fprintf('实际值: %.10f\n', sqrt(x))
y = y_new
return
end
y = y_new
end
disp(' ')
disp('警告: 未在最大迭代次数内收敛')
end
# 调用
result = sqrt_newton(2, 1e-10, 20)
注意事项
输出函数
disp 用于简单输出,fprintf 用于格式化输出
fprintf 的格式字符串必须正确匹配参数类型
- 字符串拼接使用方括号:
['str1', 'str2']
- 数值必须用
num2str 转换后才能与字符串拼接
方程求解
roots 适用于多项式,系数按降幂排列
solve 需要先用 syms 声明符号变量
mldivide (A\b) 比 inv(A)*b 更高效和稳定
ode45 使用自适应步长,适合非刚性 ODE
数值稳定性
- 避免直接计算矩阵逆,使用
mldivide
- 检查病态矩阵(大条件数)
- ODE 求解时注意刚性问题
- 多项式高次时可能数值不稳定
工作空间管理
- 在长脚本开始使用
clear() 和 clc()
- 及时清除大型变量释放内存
clear('var') 只清除指定变量
- 函数内的局部变量自动清除
调试技巧
- 使用
disp 输出中间结果
- 使用
fprintf 格式化调试信息
- 在关键位置输出变量维度:
disp(size(A))
- 使用
assert 进行单元测试和前置条件检查
- 使用
tic/toc 对热点代码进行性能计时
ODE 求解最佳实践
- 将高阶 ODE 转换为一阶系统
- 合理选择时间步长和范围
- 检查解的物理合理性
- 对于刚性问题考虑其他求解器
动态执行注意事项
eval 会降低代码可读性,应尽量避免;优先使用结构体或 Cell 数组
- 使用
eval(expr, catchExpr) 捕获潜在运行时错误
feval 适合函数名由参数决定的场景,性能与直接调用相同