2012-06-03 5 views
1

У меня есть короткий вопрос относительно команды vpa, которую можно использовать для оценки символических выражений в MatLab.MatLab - арифметика с переменной точностью

Мой учебник говорит следующее:

«Вы должны быть осторожны при использовании функции, такие как sqrt по номерам, которые по результату по умолчанию в двойной точности с плавающей запятой Вам необходимо пройти такой вход. до vpa в качестве символической строки для правильной оценки: vpa('sqrt(5)/pi'). "

Я не совсем понимаю здесь жаргон. Почему это для большинства входов, я получаю тот же ответ, нахожу ли я vpa(input) или vpa('input'), но не для квадратных корней? Например, если я нахожу vpa(sin(pi/4)) или vpa('sin(pi/4)'), я получаю точные ответы, но если я напечатаю проблему с датой выше, как vpa(sqrt(5)/pi), я не получаю тот же ответ, что и при вводе vpa('sqrt(5)/pi').

Если кто-то может объяснить это чуть подробнее, чем то, что моя книга делает выше, я был бы очень благодарен!

+0

Вам может быть интересно прочитать этот вопрос: [В MATLAB, переменные ДЕЙСТВИТЕЛЬНО двойной точности по умолчанию?] (Http://stackoverflow.com/q/4227145/97160) – Amro

ответ

4

Я не эксперт MatLab, но без кавычек, вы пропускание результата из sqrt(5)/pi в vpa():

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

С цитатами, вы прохождение выраженияsqrt(5)/pi (невычисленные и в точной форме) в vpa(), а затем сообщая MatLab для вычисления sqrt(5)/pi с переменной точностью.

+0

Спасибо! В этом есть смысл. Однако почему, когда я вхожу просто в sin (pi/4) в vpa, что не имеет значения, использую ли я кавычки? – Kristian

+0

Это должно иметь значение. Как заметил @Ben Volgt, «sin (pi/4) = sin (45 град) = sqrt (2)/2', что является иррациональным и не будет точно аппроксимироваться плавающей точкой с двойной точностью. – Blender

+0

После прочтения [docs] (http://www.mathworks.com/help/toolbox/symbolic/vpa.html) это похоже на то, что 'vpa' возвращает результат с двойной точностью, и в этом случае только точность промежуточных значений улучшается. –

1

Если вы получаете точный ответ, для начала вам не нужна арифметика с переменной точностью.

Однако sin(pi/4) должно быть точно sqrt(2)/2, что является иррациональным. Вы не должны получать точно такой же ответ с различной точностью. Возможно, вам следует проверить, как вы показываете (и округляете) результат.

+0

Спасибо. Я получаю это сейчас :). Ценить это! – Kristian

10

Никогда не предполагайте, что такое число, как vpa (sin (pi/4)), является точным до полной точности, поскольку MATLAB обычно вычисляет число внутри вызова vpa с использованием арифметики с плавающей запятой, поэтому только с точностью до 16 цифр ,

Однако похоже, что это правильно. Например, мы знаем, что

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

Давайте проверим этот результат. Я буду использовать 100 цифр точности, сравнивая как vpa, так и свои собственные инструменты HPF.

>> 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 

Итак, я думаю, анализатор признал вклад как нечто символическое набор инструментов можно вычислить более точно. Как я уже говорил, будьте осторожны. Что такое грех (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 

См., Что в первом случае анализатор нас не спас. В других случаях я заставил MATLAB вычислить правильное значение. На самом деле, немного усилий даст нам значение для sin (pi/12), как sqrt (2) * (sqrt (3) - 1)/4.

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

Дело в том, что не доверяйте парсеру, чтобы спасти вас здесь.

Редактировать: Как комментарий к замечанию Амро, я с уважением заявляю, что MATLAB делает здесь что-то интересное. Посмотрите, что vpa может вернуть правильные первые 100 цифр pi, даже когда передано pi как число двойной точности. Поскольку pi (как двойной) неверно прошло примерно 16-ю десятичную цифру, происходит что-то подозрительное.

>> vpa(pi,100) 
ans = 
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068 

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

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

В качестве доказательства этого факта давайте посмотрим, что находит HPF. HPF фактически принимает значение IEEE 754, которое хранится в двойном, затем преобразует его в номер HPF.

>> hpf(pi,100) 
ans = 
3.141592653589793115997963468544185161590576171875 

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

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

Итак, ясно, MATLAB способен распознавать пи как нечто большее, чем просто двойной точности значение оно будет передано в качестве.

Edit2:

В самом деле, немного игры говорит мне, что здесь происходит. VPA является сложным, а не парсером. Рассмотрим долю 7/13. Если мы построим его как двойное, то распечатаем значение с плавающей запятой, хранящееся в его полной славе, мы видим, что это не совсем точно. Это так, как ожидалось.

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

7/13 является повторяющимся десятичным значением. Вот правильные цифры:

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

Теперь предположим, что мы пытаемся создать тот же номер. Здесь я буду проходить 7/13 в асе дважды, но я сделаю ошибку в нижних десятичных цифрах

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

Здесь мы видим, что VPA ловит и исправляет ошибку, связанные с "Я сделал, что распознающий то, что я прошел, на самом деле тождественно то же значение, что и в 7/13.

>> vpa(0.538461538461538461777777777,100) 
ans = 
0.5384615384615384615384615384615384615384615384615384615384615384615384615384615384615384615384615385 

Конечно, если я передам значение как строку, тогда vpa ошибается.

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

Это объясняет, почему VPA способен уловить и правильно вычислить VPA (грех (пи/4), 100), к полной точности спросил. sin (pi/4) вычисляется как double, но тогда vpa видит его как число, которое совпадает с версией sqrt (2)/2 с двойной точностью.

Будьте осторожны, конечно. Например, vpa недостаточно умен, чтобы поймать этот простой сдвиг pi.

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

>> vpa(pi,100) 
ans = 
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068 
+0

просто для того, чтобы устранить любую путаницу, синтаксический анализатор не обрабатывает вход в 'vpa (sin (pi/4))' любой, отличный от вызова любой другой функции 'myFcn (sin (pi/4))' ... MATLAB сначала оценивает выражение в двойной точности перед передачей результата функции. С конечной точностью результат округляется до ближайшего десятичного значения, которое он может представлять, который VPA рассматривает как точное значение. В этот момент он может вычислить как можно больше десятичных точек ... Я полагаю, что [@AndrewJanke] (http://stackoverflow.com/a/4227530/97160) дал хорошее объяснение в вопросе, с которым я связан. – Amro

+0

Спасибо вам большое! Я искренне ценю ваш подробный ответ. – Kristian

+1

@woodchips: похоже, вы тоже правы. Когда вы вызываете 'vpa' с числовым выражением, он внутренне вызывает' vpa (sym (expr)) '. Теперь, когда 'sym' вызывается с номером, он пытается преобразовать число в« рациональную »форму, чтобы компенсировать ошибку округления ([flag = 'r'] (http://www.mathworks.com/ help/toolbox/symbolic/sym.html # inputarg_flag), что объясняет, почему VPA «исправил» ошибку, как вы показали. Если вы хотите получить те же результаты, что и ваш инструмент HPF, я предполагаю, что это будет: 'vpa (sym ('pi') - sym (pi, 'd'), 100)' – Amro

1

Последний документ на numeric to symbolic преобразование имеет ответ.

sym пытается исправить ошибку округления в входах с плавающей запятой до , возвращает точную символическую форму. В частности, sym исправляет округление ошибки в числовых входах, которые соответствуют формам p/q, pπ/q, (p/q)^(1/2), 2^q, и 10^q, где p и q являются целыми числами умеренного размера.

Таким образом, sin(pi/4) является 2^(1/2)/2 или (1/2)^(1/2) поэтому команда vpa распознает его. Однако sqrt(5)/pi не является признанной формой ввода в соответствии с документом.

Смежные вопросы