2013-03-16 3 views
0

У меня есть задача сделать такую ​​функцию максимально точной (скорость не является целью). I :float и метод средних прямоугольников. Не могли бы вы что-нибудь предложить? На самом деле, я думаю, все дело в минимизации ошибок округления поплавка. Вот что я сделал:Оптимизация вычислений с плавающей запятой

typedef float T; 

T integrate(T left, T right, long N, T (*func)(T)) { 
    long i = 0; 
    T result = 0.0; 
    T interval = right - left; 
    for(i = 0; i < N; i++) { 
     result += func(left + interval * (i + 0.5)/N) * interval/N; 
    } 
    return result; 
} 
+1

'result + = func (left + interval * (i + 0.5)/N) * interval' и' return result/N; ' – 2013-03-16 18:47:58

+0

Требуется ли это вызов указателя на функцию? Может ли он быть встроен? – Mysticial

+0

@ Мистическое да, это необходимо. Но мне не нужна скорость, мне нужна точность, так что все в порядке. –

ответ

3

Существует множество способов избежать или компенсировать округление с плавающей запятой (предложение MM, используя суммирование Kahan и т. Д.). Однако нет оснований для этого, потому что ошибки округления абсолютно затмевают ошибкой схемы интеграции; вы не получите более точный интеграл, вы получите более точную аппроксимацию неправильного результата, вычисленного по правилу средней точки. Любые такие усилия полностью теряются, за исключением особых обстоятельств.

+0

Для N = 18823 относительная погрешность -1,78814E-07 (интеграция sin (x) от 0 до Pi). Если я изменю T на двойную, это 1,16068E-09. Разница невелика, да. –

1

Попробуйте это:

{ 
    long i = 0; 
    T result = 0.0; 
    T interval = right - left; 
    for(i = 0; i < N; i++) { 
     result += func(left + interval * (i + 0.5)/N); 
    } 
    return result * interval/N; 
} 
+0

Не помогает или очень мало помогает. –

+2

Это он лучше всего вы можете получить, ИМО. Это единственное, что можно оптимизировать для точности (и, возможно, для вычисления индекса, т. Е. Части i + 0,5), вы можете использовать цикл while и увеличивать значение float вместо целочисленного значения. Но вы не можете ожидать слишком большая точность с 32-битными поплавками. –

3

I have a task to make the following function as precise as possible

Вы говорите, что вы должны использовать float, поэтому я предполагаю, что речь идет не об округлении, а о вычисляя интеграл более точно.

Я также предполагаю, что просто увеличение N - это не вариант.

Вместо того, чтобы использовать правило средней точки, мое предложение состоит в том, чтобы рассмотреть возможность использования higher-order quadrature rule (trapezoid, Simpson's etc).

+2

Правильно. Для почти любого выбора 'func' ошибка из-за схемы интеграции доминирует над ошибкой из-за округления с плавающей запятой.Единственный способ значительно повысить точность - использовать более сложный интегратор. –

+0

О, извините, я редактировал вопрос: мне нужно использовать метод средних прямоугольников. Так что все о плаваниях. Как я могу рекомбинировать их, добавлять, умножать и т. Д., Чтобы сделать вычисления более точными. –

1

Если вы хотите точно вычислить интеграл, прочитайте схемы интеграции. Некоторая домашняя рутина не даст никакой точности

Книга "Numerical recipes" (есть несколько версий, одна для С). Не смотри на это лично.

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