Ява оценить производную в точке - PullRequest
1 голос
/ 05 апреля 2011

Я сейчас пишу приложение для калькулятора. Я пытаюсь написать производную оценку в него. Формула ниже - простой способ сделать это. Обычно на бумаге вы использовали бы наименьшее возможное значение h, чтобы получить наиболее точную оценку. Проблема в том, что двойники не справляются с добавлением действительно небольших чисел к сравнительно огромным числам. Например, 4 + 1E-200 приведет к 4,0. Даже если h был всего лишь 1E-16, 4 + 1E16 фактически даст вам правильное значение, но, делая математические вычисления, оно является неточным, поскольку что-либо после 16-го места теряется и округление не может происходить правильно. Я слышал, что общее правило для дублей 1E-8 или 1E-7. Проблема в том, что большие числа не будут работать, поскольку 2E231 + 1E-8 будет просто 2E23, 1E-8 будет потеряно из-за проблем с размером.

f'(x)=(f(x+h)-f(x))/h as x approaches 0

Когда я проверяю f (x) = x ^ 2 в точке 4, то f '(4), это должно быть ровно 8 теперь я понимаю, что, вероятно, никогда не получу точно 8, но мне кажется, что наиболее точным является 1E-7 или 1E8. Самое смешное, что от 1E-9 до 1E-11 дают одинаковый ответ. Вот список ч и результатов для f(x)=x^2 at x=4

1E-7 8.000000129015916
1E-8 7.999999951380232
1E-9 8.000000661922968
1E-10 8.000000661922968
1E-11 8.000000661922968
1E-12 8.000711204658728

Вот мои вопросы:

  1. Какой лучший способ выбрать h, очевидно, имеет смысл 1E-8 или 1E-7, но как я могу выбрать h на основе x, чтобы он работал с любым числом, даже если x равно 3.14E203 или 2E-231.
  2. Сколько десятичных знаков точности я должен учитывать.
  3. Есть ли у вас какие-либо представления о том, как это делают техасские инструменты, TI 83, 84 и Inspire могут численно вычислять производные до 12 десятичных знаков или с точностью до точности и почти всегда быть правы, но максимальная точность их чисел в любом случае равна 12 цифрам, и эти калькуляторы не являются CAS, поэтому на самом деле они ничего не выводят
  4. Логично, что где-то между 1E-7 и 1E-8 есть число, которое даст мне более точный результат, есть ли способ найти это число или, по крайней мере, приблизиться к нему.

ОТВЕТИЛ

Большое спасибо, БобГ. Приложение в настоящее время планируется в 2 формах, приложение командной строки ПК. И приложение для Android. Вы будете упомянуты в особой благодарности к частям страницы About. Если вы хотите, это будет с открытым исходным кодом, но я не буду публиковать ссылки на сайт проекта, пока я не исправлю некоторые очень очень большие ошибки. На данный момент я называю это Mathulator, но название, скорее всего, изменится, потому что на него уже есть авторские права, и это звучит глупо. Я понятия не имею, когда будет запущен кандидат на релиз, в настоящий момент я не знаю, когда он будет стабильным. Но это будет очень мощно, если я смогу реализовать все, что хочу. Спасибо еще раз. Счастливого программирования.

Ответы [ 6 ]

3 голосов
/ 05 апреля 2011

Есть книга, которая отвечает на этот вопрос (и другим нравится):

Численные рецепты в C , 2-е издание, издательство Press, Vetterling, Teukolsky и Flannery. Эта книга также поставляется в версиях C ++, Fortran и BASIC. К сожалению, никакой версии Java не существует. Кроме того, я считаю, что эта книга вышла из печати, но можно купить использованные версии некоторых версий онлайн (по крайней мере, через bn.com.)

Раздел 5.7, «Числовые производные», с. 186 объясняет в точности проблему, которую вы видите с числовыми производными, и причину, по которой это происходит, а также функцию для правильного вычисления числовой производной (в C, но ее легко перевести на Java). Краткое изложение их простого приближения представлено здесь:

1) Численно, вам лучше вычислить симметричную версию:

f '(x) = (f (x + h) - f (x - h)) / 2h

2) h должно быть приблизительно (sigma_f) ^ (1/3) * x_c

, где

sigma_f = ~ дробная точность вычисления f (x) для простых функций

x_c = ~ x, если x не равен нулю.

Однако это не приводит к оптимальным производным, так как ошибка ~ (sigma_f) ^ (2/3). Лучшим решением является алгоритм Риддерса, который представлен в книге как программа на С (см. Ridders, C.J.F. 1982, Advances in Engineering Software, том 4, № 2, с. 75-76.)

2 голосов
/ 05 апреля 2011

1. Точность чисел с плавающей точкой (числа с плавающей запятой и двойные числа) зависит от абсолютного значения числа. Двойные значения имеют ~ 15 цифр точности, поэтому вы можете добавить 1 + 1e-15, но 10 + 1e-15, скорее всего, снова будет 10, поэтому вам придется сделать 10 + 1e-14. Чтобы получить значимый результат, я бы порекомендовал вам умножить эту самую 1e-8 на абсолютное значение исходного числа, это даст вам около 7 правильных цифр в производной. Что-то вроде:

double h = x * 1e-8;
double derivative = (f(x+h) - f(x)) / h;

В любом случае это приближение, скажем, если вы попытаетесь вычислить производную от sin (x) при x = 1e9, вы получите h = 10, и результат будет неверным. Но для «обычных» функций, у которых «интересная» часть близка к нулю, это будет хорошо работать.

2. Чем меньше «h», тем точнее точка, в которой вы производите выборку, но тем меньше правильных цифр производной вы получаете. Я не могу доказать это, но мое внутреннее чувство таково, что с h = x * 1e-8 вы получаете 7 = 15 - 8 правильных цифр, где 15 - точность double.

Кроме того, было бы неплохо использовать «более симметричную» формулу, она дает абсолютно правильный ответ для многочленов второго порядка:

double derivative = (f(x+h) - f(x-h)) / (2*h);
2 голосов
/ 05 апреля 2011

Прочитайте статью под заголовком «Что должен знать каждый программист о плавающей запятой» (Google для этого). Тогда вы увидите, что большинство плавающих значений представлены приблизительно в компьютерном оборудовании.

Чтобы выполнить вычисления без этого недостатка, используйте символический расчет. Но это не так эффективно, как использование плавающей запятой.

Чтобы обеспечить согласованность результатов с плавающей запятой, используйте округление до ближайшей степени 10, например, 0,1, 0,01 и т. Д. Чтобы понять, когда следует прекратить аппроксимации, используйте какой-то порог для наблюдения во время шагов аппроксимации. Например, если выполнение следующего шага аппроксимации приводит к изменению только на 0,001% к уже вычисленному значению, нет смысла продолжать аппроксимации.

Обновление У меня были классы числовых вычислений давно, но я смутно могу вспомнить, что вычитание близких чисел очень плохо, потому что, если числа очень близки, большинство надежных цифр отменяются, и у вас ненадежные цифры , Это именно то, что происходит, когда вы уменьшаете h. В этих ситуациях предлагается заменить вычитание некоторыми другими операциями. Например, вы можете переключиться на какую-то серию, до которой расширяется ваша `f (x).

Я не совсем понимаю ваш второй вопрос, потому что ответ зависит от ваших требований - «столько, сколько вы пожелаете».

Кстати, вам, возможно, повезет больше с поиском ответов на ваши вопросы на math.stackexchange.com.

Дополнительно, ссылка для посещения предоставлена ​​thrashgod: Числовое дифференцирование

1 голос
/ 05 апреля 2011

Мой вопрос: что является наиболее подходящим ч , и как его можно масштабировать до любого размера.

Как отмечено в Числовое дифференцирование , подходящим выбором для ч является кв. *, где ɛ - это машина epsilon .

0 голосов
/ 05 апреля 2011

Согласно Javadoc, 11 бит представляют экспоненту, а 52 бита представляют значащие цифры.Вне зависимости от показателя, кажется, у вас есть 52 бита для игры.Поэтому, если вы выберете h = x * 2 ^ -40, вы использовали здесь 40 бит, и точность, которую вы увидите, составляет 2 ^ -12.Отрегулируйте это соотношение в соответствии с вашими потребностями.

0 голосов
/ 05 апреля 2011

Я бы использовал BigDecimal класс для такого рода вычислений, хотя это не ответ на ваши вопросы, но это действительно улучшит точность арифметики с плавающей точкой.

...