Правило Симпсона требует вечно работать в Python - PullRequest
0 голосов
/ 09 октября 2018

Я написал следующую функцию для оценки определенного интеграла функции с правилом Симпсона:

def fnInt(func, a, b):
    if callable(func) and type(a) in [float] and type(b) in [float]:
        if a > b:
            return -1 * fnInt(func, b, a)
        else:
            y1 = nDeriv(func)
            y2 = nDeriv(y1)
            y3 = nDeriv(y2)
            y4 = nDeriv(y3)
            f = lambda t: abs(y4(t))
            k = f(max(f, a, b))
            n = ((1 / 0.00001) * k * (b - a) ** 5 / 180) ** 0.25
            if n > 0:
                n = math.ceil(n) if math.ceil(n) % 2 == 0 else math.ceil(n) + 1
            else:
                n = 2
            x = (b - a) / n
            ans = 0
            for i in range(int((n - 4) / 2 + 1)):
                ans += (x / 3) * (4 * func(a + x * (2 * i + 1)) + 2 * func(a + x * (2 * i + 2)))
            ans += (x / 3) * (func(a) + 4 * func(a + x * (n - 1)) + func(b))
            return ans
    else:
        raise TypeError('Data Type Error')

Однако кажется, что всякий раз, когда я пытаюсь использовать эту функцию, для ее создания требуется вечностьвыход.Можно ли переписать этот код, чтобы он занимал меньше времени?

1 Ответ

0 голосов
/ 09 октября 2018

Как один из упомянутых комментариев, профилирование кода покажет вам замедления.Возможно, nDeriv медленно.Если у вас нет инструмента профилирования, вы можете поместить time() вызовов в каждую часть кода и распечатать результаты.Больше информации здесь: Измерять время, прошедшее в Python?

Итак, если замедление заканчивается в вашем цикле for, вот несколько вещей, которые вы можете попробовать:

  1. Python может вычислять условие цикла на каждой итерации:

    for i in range(int((n - 4) / 2 + 1)):

вычислять int((n - 4) / 2 + 1) один раз перед циклом.

Не пересчитывайте вещи внутри циклов, которые не меняются.Например, x / 3 будет пересчитываться при каждой итерации цикла, но он никогда не изменится.Сделайте это до начала цикла.

Аналогично, вы делаете 2 * i дважды за каждую итерацию цикла.

Сложение происходит быстрее, чем умножение.Аргументы функции могут быть переписаны следующим образом:

xi = x * i a1 = a + xi + xi + x a2 = a1 + x

, а затем, сделав еще один шаг, вы также можете сделать еще xi какаккумулятор.То есть начните с x = 0, затем каждую итерацию просто x += x

Это, вероятно, очевидно, но если func() сложно вычислить, эта функция будет экспоненциально медленной.

Возможно, Python делает для вас множество простых оптимизаций, поэтому они могут не помочь, но просто хотели поделиться некоторыми идеями.

...