The problem is that when I use vpa(U(x,t), 7) to get the solution with 7-digit decimal precision, MATLAB still outputs a very long and complicated expression. how do I fix it?

3 views (last 30 days)
clc
clf
syms x t u(x,t) u0 a1(t) a2(t)
xmin = 0; xmax = 1; init_val = 5*exp(x);
phi = [x^2-x, 3/2*x^3-3/2*x]
phi = 
%phi = [3*x-6*x^2+3*x^3, 3*x^2-3*x^3]
n = numel(phi);
u = vpa(5*exp(x+t) + a1*phi(1) + a2*phi(2),9)
u(t) = 
u0 = vpa(subs(u, [x, t], [x,0]),9);
A = sym('a0',[1 n])
A = 
in_eqs = [];
for i = 1:n
in_eqs = [in_eqs int((5*exp(x)+phi(1)*A(1)+phi(2)*A(2)-init_val)*phi(i),xmin,xmax) == 0];
end
in_eqs.'
ans = 
sol = solve(in_eqs);
if(isa(sol,'struct')==1)
sol = struct2cell(sol);
for i = 1:n
A(i) = sol{i};
end
else
A = sol;
end
vpa(A,9)
ans = 
eq = [];
for i = 1:2
eq = [eq int((diff(u,t)-diff(u,x,2)-(2*x+1)*(diff(u,x))-x^2*u-5*exp(x+t))*phi(i),x,0,1)==0];
end
sol = dsolve([eq, a1(0) == A(1), a2(0)==A(2)]);
U(x,t) = vpa(subs(u, [a1 a2], [sol.a1, sol.a2]),7)
U(x, t) = 

Answers (2)

Torsten
Torsten on 13 May 2025
Edited: Torsten on 13 May 2025
The documentation says
xVpa = vpa(x,d) uses at least d significant digits instead of the value of digits.
That means for your case that MATLAB will output with max(32,7) = 32 digits.
To reduce the output precision, set
digits(7)
U(x,t) = vpa(subs(u, [a1 a2 ], [sol.a1, sol.a2]))
e.g.
Of course, you won't get back a simple decimal number with 7 digits because x and t are still unspecified in U(x,t). Only the coefficients in the expressions for U(x,t) are reduced to 7 digits in length.
  3 Comments
Walter Roberson
Walter Roberson on 13 May 2025
The interal struct() of a symbolic expression has three parts:
  1. 's' -- a field that is a character vector representing the name of a symbolic variable if the expression is a symbolic variable, but the field is a character vector of the form '_symans_[[32,9,648]]' if the expression is not a simple symbolic variable. The _symans_ form is a reference to an internal symbolic engine table of values and the 32,9,648 is a reference to a specific value within the table.
  2. 'mathmlOutput' -- a field that is populated mostly for LiveScript, and holds a MathML representation of the symbolic value
  3. 'Digits' -- the number of digits to display for the expression
When you vpa() a symbolic expression, vpa() converts rational values to symbolic floating point values, and calculates out expressions that can be calculated out... and sets the Digits field of the resulting expression. The number of digits you specify for vpa() only matters if it exceeds the digits() setting; otherwise the digits() setting is used for calculation and the output is trimmed for display purposes by setting the Digits field
When you simplify() the output of vpa(), the 's' field returned by the vpa() is examined, but the Digits field is ignored. So as soon as you simplify() the output of vpa(), the number of display digits is reset.

Sign in to comment.


Walter Roberson
Walter Roberson on 13 May 2025
Observe:
a1 = vpa(sym(pi), 7)
a1 = 
3.141593
a2 = vpa(a1, 10)
a2 = 
3.141592654
a3 = vpa(a2, 15)
a3 = 
3.1415926535898
a4 = a3 - pi
a4 = 
double(a4)
ans = 3.4302e-15
From this we deduce that vpa() controls the display digits, but leaves at least 8 internal guard digits.
Then when you do
U(x,t) = vpa(subs(u, [a1 a2], [sol.a1, sol.a2]),7)
the vpa() might have controlled the display digits, but you assigned in a function-building form, and the function-building form does not know anything about the restriction on display digits
  4 Comments
Walter Roberson
Walter Roberson on 13 May 2025
You can hack it using mapSymType
syms x t u(x,t) u0 a1(t) a2(t)
xmin = 0; xmax = 1; init_val = 5*exp(x);
phi = [x^2-x, 3/2*x^3-3/2*x]
phi = 
%phi = [3*x-6*x^2+3*x^3, 3*x^2-3*x^3]
n = numel(phi);
u = vpa(5*exp(x+t) + a1*phi(1) + a2*phi(2),9)
u(t) = 
u0 = vpa(subs(u, [x, t], [x,0]),9);
A = sym('a0',[1 n])
A = 
in_eqs = [];
for i = 1:n
in_eqs = [in_eqs int((5*exp(x)+phi(1)*A(1)+phi(2)*A(2)-init_val)*phi(i),xmin,xmax) == 0];
end
in_eqs.'
ans = 
sol = solve(in_eqs);
if(isa(sol,'struct')==1)
sol = struct2cell(sol);
for i = 1:n
A(i) = sol{i};
end
else
A = sol;
end
vpa(A,9)
ans = 
eq = [];
for i = 1:2
eq = [eq int((diff(u,t)-diff(u,x,2)-(2*x+1)*(diff(u,x))-x^2*u-5*exp(x+t))*phi(i),x,0,1)==0];
end
sol = dsolve([eq, a1(0) == A(1), a2(0)==A(2)]);
U_ = subs(u, [a1 a2], [sol.a1, sol.a2]);
U_ = mapSymType(U_, 'constant', @(V)round(V,7))
U_(t) = 
U(x,t) = U_
U(x, t) = 
James Tursa
James Tursa on 13 May 2025
Edited: James Tursa on 13 May 2025
Note that vpa is likely using binary (or hex?) floating point calculations in the background, not decimal or BCD. So the number of decimal digits requested is fuzzy at best, because vpa needs to map the decimal request into the number of actual binary digits used in the background. See here for an example:

Sign in to comment.

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!