贡献者: addis
Matlab 的符号计算需要符号计算工具箱,取决于你的证书类型,可能需要额外购买。另外需要提醒的是,虽然 Matlab 和 Python 都有符号计算功能,但在符号计算领域 Mathemtica 才更为主流,其默认界面也更适合符号计算。
sym
。可以用 syms 变量1 变量2 ...
声明变量类型为 sym
。例如 syms x y z;
。
syms f(x)
定义一个符号函数 f
。该命令会同时创建符号变量 x
和符号函数 f(x)
(symfun
类型,没有具体定义)。接下来可以用 f(x) = x^2
对其定义,这相当于运行 syms x; f(x) = x^2;
。
sym
类型的变量,例如 x^2
就是 sym
类型的表达式 expr = x^2
,那么用 class(expr)
可以验证 expr
的类型也是 sym
。
syms
一次声明几个符号变量,也可以使用 sym(字符串)
其中字符串只能是变量名或数字。例如 syms x; expr = x^2;
得到的 expr
和 expr = sym('x')^2;
得到的 expr
是等效的。
str2sym(字符串)
可以把字符串转换为符号表达式。例如 str2sym('pi')
或 str2sym('sqrt(3)/2')
。注意在较新版的 Matlab 中,sym('pi')
将得到名为 pi
的符号变量,而不是圆周率。
diff(sym('x')^2)
。若要求偏导,diff(sym('x')^2 * sym('y')^3)
默认对 x
求偏导(x
是通过 symvar(expr, 1)
决定的),结果是 y
求偏导,如 diff(sym('x')^2 * sym('y')^3, sym('y'))
,或者更简洁地,diff(sym('x')^2 * sym('y')^3, 'y')
。这是因为,如果若函数的一个形参需要符号表达式,但实参使用了字符串或者数值,那么 Matlab 就会自动将其用 sym()
函数进行转换。建议总是声明对哪个变量求偏导。若不声明,则会通过 symvar(expr, 1)
决定。expr
也可以是 symfun
类型的。
diff(f, var, n)
可以求高阶导数。diff(f, y, z)
求混合偏导。
sym('2')
或 sym('7/3')
,但这仅限于分式,不允许诸如 sym('sqrt(2)')
这样的用法,应该用 str2sym('sqrt(2)')
或者 sqrt(sym(2))
。
sym(数值)
。例如 sqrt(sym(2))
的结果是表达式 sqrt(2) = 1.414...
。由于符号计算是精确无误差的,无理数 sym(数值)
会自动猜测 数值
所代表的根式,例如 sym(0.866025403784439)
的结果是表达式 sym(pi)
的结果是精确的圆周率符号 sym(sqrt(pi))
就只能猜出一个近似的分数。
num2sym(双精度)
。
sym(...)
作用在一个数组上(可以是任何上述类型),那么则逐个元素作用,并生成 sym
类型的数组。
sym
类型和一个 double 类型进行 +, -, *, /, ^
等运算时,double
类型的数会自动被 sym()
函数转换为 sym
类型。例如 sym(1)/3
和 sym(1)/sym(3)
是等效的。这样可以让输入更简洁。
subs(符号表达式,符号变量, 新表达式)
可以把表达式中的所有 符号变量
替换为 新表达式
。例如 subs(sin(sym('x')), 'x', 'y')
相当于 subs(sin(sym('x')), sym('x'), sym('y'))
,结果是 subs(sin(sym('x')), 'x', pi/4)
的结果是 新表达式
是一个数组,则依次对每个元素进行替换,输入一个 sym
类型的数组。
double()
,例如 double(sqrt(sym(2)))
结果是 1.414...
,是一个双精度数值,误差就是双精度类型的相对误差 eps
,约为 注意变精度计算功能往往和符号计算一同使用,但这两个功能从实现来看是完全不同的。变精度计算和双精度一样本质上还是数值浮点计算,计算过程存在数值误差。只不过我们可以规定每个变量的有效数字为任意多,而不是统一使用双精度类型的 15-16 位有效数字。
Matlab 的变精度计算并不自带误差追踪功能,例如两个十分相近的数相减,返回的小数位中可能大部分都是错的。而 Mathematica 的做法是返回更少小数位,但保证最后一位是对的。
double(符号表达式)
返回双精度结果,vpa(符号表达式, 位数)
可以计算符号表达式的任意位有效数字结果,例如 vpa(sqrt(sym('2')), 50)
计算 'sym'
类型的对象而不是 'double'
类型。
vpa
返回的类型也是 'sym'
,但它是有误差的,本质上是一个类似 double
的浮点类型。vpa()
就是 variable precision arithmetic,变精度计算。我们姑且把这种有误差的 sym
数字称为变精度浮点数。我们可以把变精度浮点数当作 double
类型的拓展。double
在十进制下只有约 15-16 位有效数字,而变精度浮点数的有效数字位数可以任意指定。
sym
类型的对象 x
是否有误差,只需要在命令行中把它显示出来(可以使用 disp()
函数,也可以直接运行 x
不加分号)。如果显示中出现了小数点,那么他就是变精度浮点数。sym
类型的整数,无论有多少位,如果没有误差则会把每一位显示出来而不是用科学计数法(因为科学计数法带小数点,表示有误差)。
vpa()
函数会输出变精度浮点数,另一种方法如 sym('12.3')
或者 sym('1.23e1')
(用 vpa
也一样),运行后显示结果为 12.3
,存在小数点,所以是变精度浮点数。相比之下,sym('123/10')
结果显示为 sym('1.2345678902234567890323456789042345678905234567890') - sym('1.2345678902234567890323456789042345678905234500000')
返回的是 6.789000000000011835767836416814e-45
而不是 6.789e-45
。而 Mathematica 就会返回 6.789e-45
。
vpa()
和 sym()
中如果有效数字超过 15-16,要用引号,否则会先转换为 double,超出 15-16 位的部分丢失。
vpa(数值)
和 sym(数值)
一样会自动猜测 数值
所代表的根式或符号,结果相当于 vpa(sym(数值))
。例如 vpa(0.866025403784439)
的结果是表达式 sym(pi)
的结果是精确的圆周率符号 vpa(0.866025403784439) - vpa(str2sym('sqrt(3)/2'))
结果为零,又例如 vpa(pi, 1000)
可以得到圆周率的 1000 位有效数字。
vpa
猜测,则应该使用引号,例如 vpa('0.866025403784439') - vpa(str2sym('sqrt(3)/2'))
不为零。使用引号可以在当前 digits
设置的精度内最精确地表示引号内的数字。验证:vpa('1.866025403784439') - vpa('1.866025403784438')
vpa(1+1e-14)
得 1.0
,sym(1+1e-14)
得 1
。sym(pi+1e-14)
得 pi
。这有时候可能反而会造成麻烦。
vpa(双精度)
会先把 双精度
变为 ieee 二进制表示,然后在后面添零拓展精度。验证:num2bin2(vpa(1.234567890223456789))
和 num2bin2(1.234567890223456789)
结果相同。
num2vpa(双精度, 有效数字)
。
gamma
,hypergeom
)会保证输出结果的最后一位正确(可以对比 Mathematica 结果),但由于上一条中误差,自己写的函数则无法保证。
hypergeom
只有符号工具箱中有,所以参数直接输入 double 就行,gamma
函数有普通的版本(只支持 double 实数),如果输入 double 复数会出错,这是只需要用 gamma(vpa(复数))
即可。
1 + sym('1e-40') - 1
的结果显示为 0.0
,而 1 + sym(10)^(-40) - 1
的结果显示 1/10000....
(40 个 0)。
digits(整数)
设置,如果不设置,则默认是 32 位。也可以使用不含自变量的 digits()
查看当前设置的位数。实际上的有效位数比设置的要多 8 位,所以默认是 40 位。这可以用 “双精度和变精度浮点数测试(Matlab)” 中的 digits2
验证。
digits
函数是控制全局的,如果设置了 digits
以后调用某函数,那么函数内部的变精度计算也都会采用同样精度。
digits(32)
后,vpa(sym(pi)/2, 50) + vpa(sym(pi)/2, 100)
的结果仍然是 32 位有效数字。
digits
以后,字符串 vpa 如 vpa('1.2345...')
相当于 vpa('1.2345...', 有效数字)
(实际上还要多 8 位,也就是最后一位后面有 8 个零),若两个精度高于 digits
设置的 vpa('数字字符串')
进行运算,就先把高精度的有效数字减少为低精度的再进行运算。但如果其中一个 vpa('数字字符串')
精度低于 digits
的设置,就先变为 digits
设置的精度。例子:先设置 digits(32)
,则 vpa('1.2345678902234567890323456789042345678905234567890623456789') - vpa('1.23456789022345678903234567890423456')
的结果有 8 位有效数字。另一个例子 vpa('1.2345678902234567890323456789') - vpa('1.2345678902234567890323456788')
结果有 12 位有效数字。
digits(50)
,再运行 (1 + sym('1e-40')) - 1
就会得到 0.000...000999...99938892...
,这就比默认的 32 位有效数字计算精确多了,但还是存在误差。
sym('1.2')*sqrt(2*sym('x'))
,结果是 sym(12/10)*sqrt(2*sym('x'))
得到精确的
由于一些特殊函数若用双精度计算,往往在一些区间产生较大误差。所以 Matlab 决定只使用任意精度来计算。以复数域的 gamma(1+1i)
则会出错,因为 Matlab 中非符号计算版本的 gamma
函数只支持 double
类型的实数输入。所以要调用符号计算工具箱提供的 gamma()
,就输入一个 sym
类型的变量即可。例如 gamma(vpa(1+1i))
返回 0.49801... - 0.15494...i
,又例如 gamma(sym(1+1i))
返回表达式 gamma(1 + 1i)
。这是因为 vpa(1+1i)
是变精度浮点数,可以显示为小数,而 sym(1+1i)
不存在误差,不能显示为小数。当然,我们也可以用例如 vpa(gamma(sym(1+1i)), 50)
来求任意位有效数字。
友情链接: 超理论坛 | ©小时科技 保留一切权利