Why does vpa give a sym class variable?

15 Ansichten (letzte 30 Tage)
Kareem Elgindy
Kareem Elgindy am 2 Nov. 2022
Beantwortet: Steven Lord am 2 Nov. 2022
>> vpa(cos(10))
ans =
-0.83907152907645243811174395887065
Now, ans is 1x1 sym in the Workspace. Why? Isn't sym mean symbolic number/variable? The above result is not exact, so why it is a sym variable? Can someone explain?

Akzeptierte Antwort

Walter Roberson
Walter Roberson am 2 Nov. 2022
MATLAB processes all of the parameters before it calls the function. So it first processes cos(10) . 10 is a double precision number in that context, and you ask for cos() of it, which is cosine of 10 radians. That is all still in double precision, so the library cos routine is called, which probably ends up invoking a hardware cosine instruction to calculate the resulting double precision number.
Then vpa() is being called, passing in a double precision number. vpa() is a function from the symbolic toolbox, and for most of the functions in the symbolic toolbox, the first thing that is done with input double precision numbers is to convert them to symbolic numbers. The default conversion is 'r' .
The 'r' conversion first looks to see if the input is close to a simple rational multiple of π with a denominator of no more than 1000 and if so then it converts it to that fraction times symbolic π . If it does not appear to be a simple rational multiple of π then there are a series of other conversion attempts made, such as looking to see if it appears to be the square root of a rational number, or close to an integer, such as sym(1-eps) will convert to symbolic 1 exactly; also values "close" to rational numbers are looked for. If none of those special conversions hold, then the default 'r' conversion method converts to a rational fraction with a power-of-2 denominator based upon the internal base-2 binary floating point representation of double precision numbers.
So after the automatic conversion, the value might be a symbolic multiple of π or might be a symbolic relationship to a square root such as 2*10^(1/2) or might be a symbolic rational fraction
c10 = cos(10)
c10 = -0.8391
sym(c10)
ans = 
That symbolic -757<etc> fraction is what cos(10) double precision happens to convert to.
Then the vpa() function is given control to do whatever is appropriate with that symbolic rational fraction. When given only a single parameter, the default would be to take a symbolic floating point approximation of the rational fraction (or other symbolic number as appropriate) with the number of digits to be used internally being the current digits() setting plus 5 . The default digits setting is 32, so the rational fraction would be approximated to 32+5 = 37 decimal digits, returning a symbolic floating point result with 37 internal digits.
Then you implicitly ask to display the result. The default behaviour to display symbolic floating point numbers is to display then to the current setting of digits(), no matter how many internal digits were used. So since digits() has not changed, 32 of the 37 decimal digits would be displayed.
The result is not a double precision number because it is part of the entire symbolic processing ecosystem.
Remember that the number of digits can change, and the number of digits can be specified in the vpa() call. It would be... strange... if the result was double precision if the number of specified digits or the number of default digits was 15 or fewer and the result does not contain any unresolved symbolic variables or expressions... and to be returned as symbolic otherwise. The user would not be able to guess what the result would be.
Consider for example,
syms x
for K = 0 : 3
results(K+1) = vpa(cos(1+x^K))
end
x^0 is symbolic 1 so 1+x^0 would be 1+symbolic 1 and cos(1+symbolic 1) would be cos(symbolic 2) which is cos() of a constant. Under your proposal, vpa() of that should return a double precision number. If results did not get initialized before that, then results would be initialized as double precision under your proposal. But then when K=1 then cos(1+x^1) would be cos(1+x) which vpa() would convert to cos(x + symbolic floating point 1.0) . And then you would attempt to assign it to the results array which, under your proposal, would be double precision. But that would be an error.
Whereas under the actual behaviour, vpa(cos(2)) would be a symbolic floating point number, and results() would get initialized to be symbolic, and would have no problem storing the symbolic cos(x+1.0) the next round.

Weitere Antworten (1)

Steven Lord
Steven Lord am 2 Nov. 2022
Another simpler point to what Walter Roberson said: we don't want you to have to check the class of the output returned by vpa each and every time you call it.
syms x
f1 = x-x
f1 = 
0
f2 = x^2-x
f2 = 
v1 = vpa(f1)
v1 = 
0.0
v2 = vpa(f2)
v2 = 
whos
Name Size Bytes Class Attributes cmdout 1x33 66 char f1 1x1 8 sym f2 1x1 8 sym v1 1x1 8 sym v2 1x1 8 sym x 1x1 8 sym
Under the current behavior, both v1 and v2 are sym arrays.
Under the behavior it's implied that you expected, you'd have to check whether or not v1 or v2 were sym arrays before you tried to operate on them with functions that were only defined for sym objects (or had different behavior for sym.) In that case v1 probably wouldn't be a sym, it would be a number. That could cause problems down the line, if you tried to differentiate the functions in v1 and v2. Note the big difference between d1 and d1a.
d1 = diff(v1)
d1 = 
0.0
d2 = diff(v2)
d2 = 
d1a = diff(0)
d1a = []

Tags

Produkte


Version

R2022b

Community Treasure Hunt

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

Start Hunting!

Translated by