MatLab - variable precision arithmetic

寵の児 提交于 2019-12-11 05:19:50

问题


I have a brief question regarding the vpa command one may use to evaluate symbolic expressions in MatLab.

My textbook says the following:

"You need to be careful when you use functions such as sqrt on numbers, which by default result in a double-precision floating-point number. You need to pass such input to vpa as a symbolic string for correct evaluation: vpa('sqrt(5)/pi')."

I don't quite understand the jargon here. Why is it that for most inputs I get the exact same answer whether I type vpa(input) or vpa('input'), but not for square roots? For instance, if I type vpa(sin(pi/4)) or vpa('sin(pi/4)'), I get the exact same answers, but if I type the give problem above as vpa(sqrt(5)/pi), I do not get the same answer as when I type vpa('sqrt(5)/pi').

If someone could explain this in a little more detail than what my book does above, I would be very grateful!


回答1:


I'm no MatLab expert, but without quotes, you're passing the result of sqrt(5)/pi into vpa():

  vpa(sqrt(5)/pi)
= vpa(0.7117625434171772)

With quotes, you're passing the expression sqrt(5)/pi (unevaluated and in exact form) into vpa() and then telling MatLab to compute sqrt(5)/pi with variable precision.




回答2:


Never assume that a number like vpa(sin(pi/4)) is exact to the full precision, because MATLAB will generally compute the number inside the call to vpa using floating point arithmetic, so only accurate to about 16 digits.

However, it appears that it is correct here. For example, we know that

sin(pi/4) == sqrt(2)/2

Lets test that result. I'll use 100 digits of precision, comparing both vpa and my own HPF tools.

>> vpa(sin(pi/4),100)
ans =
0.7071067811865475244008443621048490392848359376884740365883398689953662392310535194251937671638207864

>> vpa(sqrt(sym(2))/2,100)
ans =
0.7071067811865475244008443621048490392848359376884740365883398689953662392310535194251937671638207864

>> sqrt(hpf(2,100))/2
ans =
0.7071067811865475244008443621048490392848359376884740365883398689953662392310535194251937671638207864

>> sin(hpf('pi',100)/4)
ans =
0.7071067811865475244008443621048490392848359376884740365883398689953662392310535194251937671638207864

So, my guess is the parser has recognized the input as something the symbolic toolbox can compute more accurately. As I said before, be careful though. What is sin(pi/12)?

>> vpa(sin(pi/12),100)
ans =
0.25881904510252073947640383266843855381011962890625

>> vpa('sin(pi/12)',100)
ans =
0.2588190451025207623488988376240483283490689013199305138140032073150569747488019969223679746942496655

>> vpa(sin(sym('pi')/12),100)
ans =
0.2588190451025207623488988376240483283490689013199305138140032073150569747488019969223679746942496655

>> sin(hpf('pi',100)/12)
ans =
0.2588190451025207623488988376240483283490689013199305138140032073150569747488019969223679746942496655

See that in the first case, the parser did not save us. In the others, I forced MATLAB to compute the correct value. In fact, a bit of effort will give us the value for sin(pi/12), as sqrt(2)*(sqrt(3) - 1)/4.

>> DefaultNumberOfDigits 100
>> (sqrt(hpf(3)) - 1)*sqrt(hpf(2))/4
ans =
0.2588190451025207623488988376240483283490689013199305138140032073150569747488019969223679746942496655

The point is, do not trust the parser to save you here.

Edit: As a test of Amro's comment, I respectfully state that MATLAB IS doing something of interest here. See that vpa is able to return the correct first 100 digits of pi, even when passed pi as a double precision number. Since pi (as a double) is not correct past about the 16th decimal digit, there is something fishy going on.

>> vpa(pi,100)
ans =
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068

>> vpa('pi',100)
ans =
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068

vpa('pi',100) - vpa(pi,100)
ans =
0.0

As a test of that fact, lets look at what HPF finds. HPF actually takes the IEEE 754 value, as stored in a double, then converts it to an HPF number.

>> hpf(pi,100)
ans =
3.141592653589793115997963468544185161590576171875

>> hpf('pi',100)
ans =
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068

>> hpf('pi',100) - hpf(pi,100)
ans =
0.0000000000000001224646799147353177226065932275001058209749445923078164062862089986280348253421170679821480800000000

So clearly, MATLAB is able to recognize pi as something more than just the double precision value it will be passed in as.

Edit2:

In fact, a bit of play tells me what is happening here. VPA is the tricky one, not the parser. Consider the fraction 7/13. If we build it as a double, then print out the floating point value stored in its full glory, we see it is not truly exact. This is as expected.

>> sprintf('%.100f',7/13)
ans =
0.5384615384615384359179302009579259902238845825195312500000000000000000000000000000000000000000000000

7/13 is a repeating decimal value. Here are the correct digits:

>> vpa('7/13',100)
ans =
0.5384615384615384615384615384615384615384615384615384615384615384615384615384615384615384615384615385

Now, suppose we try to create the same number. Here I'll pass 7/13 in asa double, but I'll make a mistake in the bottom decimal digits

>> sprintf('%.100f',0.538461538461538461777777777)
ans =
0.5384615384615384359179302009579259902238845825195312500000000000000000000000000000000000000000000000

Here we see that vpa catches and corrects the 'error' I've made, recognizing that what I passed in is actually identically the same value as when I passed in 7/13.

>> vpa(0.538461538461538461777777777,100)
ans =
0.5384615384615384615384615384615384615384615384615384615384615384615384615384615384615384615384615385

Of course, if I pass in the value as a string, then vpa gets it wrong.

>> vpa('0.538461538461538461777777777',100)
ans =
0.538461538461538461777777777

This explains why vpa is able to catch and correctly compute vpa(sin(pi/4),100), out to the full precision asked. sin(pi/4) is computed as a double, but then vpa sees it as a number that is the same as a double precision version of sqrt(2)/2.

Be careful of course. For example, vpa is not smart enough to catch this simple shift of pi.

>> vpa(pi + 1,100)
ans =
4.141592653589793115997963468544185161590576171875

>> vpa(pi,100)
ans =
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068



回答3:


If you're getting the exact same answer, you didn't need variable precision arithmetic to begin with.

However, sin(pi/4) should be exactly sqrt(2)/2, which is irrational. You should not get exactly the same answer from different precision. Perhaps you should check how you're displaying (and rounding off) the result.




回答4:


The latest doc on numeric to symbolic conversion has the answer.

sym tries to correct the round-off error in floating-point inputs to return the exact symbolic form. Specifically, sym corrects round-off error in numeric inputs that match the forms p/q, pπ/q, (p/q)^(1/2), 2^q, and 10^q, where p and q are modest-sized integers.

Thus, sin(pi/4) is 2^(1/2)/2 or (1/2)^(1/2) so the vpa command recognizes it. However, sqrt(5)/pi is not a recognized input form according to the doc.



来源:https://stackoverflow.com/questions/10872933/matlab-variable-precision-arithmetic

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!