Fonksiyonumu Nasıl Daha Hızlı Hale Getirebilirim?

Arkadaşlar merhaba ,

simpson 1/3 kuralına göre integral hesaplayan bir fonksiyon yazdım. Bu fonksiyonun işlem süresini kısaltmak için farklı olarak ne yapabilirim ?

def integral(func,baslangıc_noktası,bitis_noktası):

    try:
        delta_x: float = 0.000001

        n = (bitis_noktası - baslangıc_noktası) / delta_x
        n = int(round(n, 0))

    except TypeError:
        pass

    if n//2 == 0 :

        n =n
    elif n//2 == 1:

        n = n+1


    liste1 = list()


    liste1.append(func(baslangıc_noktası))
    liste1.append(func(bitis_noktası))

    for i in range(1,n-1,2):
        liste1.append(4*func(baslangıc_noktası+i*delta_x))


    for i in range(2,n-2,2):

        liste1.append(2*func(baslangıc_noktası+i*delta_x))

    integral_degeri = (delta_x/3)*sum(liste1)

    return integral_degeri



import math

a = lambda x :(math.sin(x)**2)/(math.cos(x)**2)

print(integral(a,0,10))
1 Beğeni

Fonksiyonunuzu nasıl daha hızlı hale getirebilirsiniz bilmiyorum ama integral hesaplamaları yapmak istiyorsanız scipy kütüphanesinin integrate modülündeki quad fonksiyonunu kullanabilirsiniz.

Bu arada math modülünün sin, cos, tan gibi trigonometrik fonksiyonlarını kullanırken dikkat etmeniz gereken bir durum var.

from math import cos, sin, radians
print(sin(90))
# 0.8939966636005579
# Halbuki sin(90) = 1'dir.
# Bu yüzden fonksiyonu şöyle kullanmak gerekir.
print(sin(radians(90))
# 1.0
print(cos(radians(0))
# 1.0

arcsin veya arccos işlemlerinde ise degrees kullanmak gerekir.

from math import asin, acos, degrees
print(degrees(asin(1))
# 90
print(degrees(acos(0))
# 90 
2 Beğeni

Cok buyuk n secmissin. (Sayilarin farkinin 1,000,000 kati; ornekte 10,000,000) Onden guzel bir n secip Δx'i ona gore hesaplamak gerekmiyor mu?

Bir de sin²(x)/cos²(x) verdigin aralikta tanimsiz, cunku cos(x) 0 oluyor.

@aib
Rica etsem aşağıdaki kodları inceler misiniz? Acaba bir hata mı yapıyorum merak ettim.

Soruyu şöyle anladım ben: f(x) = sin²(x) / cos²(x) fonksiyonunun 0 ile 10 aralığındaki integrali nedir? Ve bu soruyu kodlara dönüştürmeye çalıştım.

from numpy import sin, cos, radians
from scipy.integrate import quad

integrand = lambda x: sin(radians(x)) ** 2 / cos(radians(x)) ** 2

f = lambda: quad(func=integrand, a=0, b=10)[0]

print(f())

Aldığım çıktı şöyle oldu:

0.10279180887972904
1 Beğeni

Hocam n i büyük secmemin nedeni hata değerini minimize etmek için. Bununla ilgili bir teori var mı bilmiyorum açıkçası. analitik çözümle arasında %0.1 bir hata da kabul edilebilir belki n’i ona göre ayarlasam daha iyi olabilir. Fakat işte analitik çözüm değeri elimizde olmadığı için n değerini çok büyük alıp garantiye almak istedim.

ikinci soru , hocam örnek olarak verdiğim fonksiyonun integral alınmış hali tanx - x oluyor yani tanımsız olmuyor.

Yani Belki kod ameliliği yapmışımdır diye düşündüm ondan böyle bir soru sordum , farklı bir çözümde olabilir belki diye :slight_smile:

1 Beğeni

cevaplarınız için teşekkür ederim.

açıkçası scipy’ın integral hesaplama şekilleride yamuk , ve simpson kuralları gibi sanırım. benzer kodu radian cinsinden 0,10 arasında ben hesapladığımda şu sonucu elde ediyorum.

0.0017940267437353738

0 ,45 arasında ise radyan cinsinden olacak şekilde

0.21459967321734655
sonuçlarını elde ediyorum ve doğru sonuçlar bu şekilde.

sizde neden öyle bir sonuç çıktı anlayamadım bende :slight_smile:

1 Beğeni

Sizin yazdığınız fonksiyonla hesaplama yaptığım zaman yine aynı değeri aldım. :slight_smile:

0.10279174669732347

sorunun 0,45 radyan arasında ki cevabı elimde olduğu için oradan kontrol sağlıyorum.Bende aynı fonksiyon da hesaplıyorum neden farklı hesap cıkıyor acaba ?

a fonksiyonunu nasıl yazdınız bir görebilir miyim?

Aşağıdaki kodları çalıştırın sonucuna bakın, sonra sizin farklı sonuç aldığınız kodlarla bir karşılaştırın isterseniz.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-


def integral(func,baslangıc_noktası,bitis_noktası):

    try:
        delta_x: float = 0.000001

        n = (bitis_noktası - baslangıc_noktası) / delta_x
        n = int(round(n, 0))

    except TypeError:
        pass

    if n//2 == 0 :

        n =n
    elif n//2 == 1:

        n = n+1


    liste1 = list()


    liste1.append(func(baslangıc_noktası))
    liste1.append(func(bitis_noktası))

    for i in range(1,n-1,2):
        liste1.append(4*func(baslangıc_noktası+i*delta_x))


    for i in range(2,n-2,2):

        liste1.append(2*func(baslangıc_noktası+i*delta_x))

    integral_degeri = (delta_x/3)*sum(liste1)

    return integral_degeri



from math import radians, cos, sin

a = lambda x :(sin(radians(x))**2)/(cos(radians(x))**2)

print(integral(a,0,10))

Sonuç:

0.10279174669732347

ben a fonksiyonunu şu şekilde tanımladım ;

a = lambda x :(math.sin(x)**2)/(math.cos(x)**2)

şu şekilde çalıştırdım ;

print(integral(a,0,(math.pi)*10/180)

aldığım sonuç
0.0017940267437353738

sizin attığınız fonksiyona göre evet sizin değeriniz çıkıyor.

0 , 45 arasında ki integral değeri ise

12.295777513082243

yani fonksiyonun tanımlanma şeklinden dolayı bir farklılık var. Sizin tanımladığınız şekilde nasıl bir algılama yapıyor anlayamadım deneme yapıp bakayım bi :slight_smile:

Şöyle yazmanız gerekmez miydi?

a = lambda x :(math.sin(math.radians(x))**2)/(math.cos(math.radians(x))**2)

Şu mesajı hatırlatırım:

aslında sizin dediğiniz de doğru ben direk sınır şartlarını radyan cinsinde gönderdiğim için bir fark olmuyor. radyan cinsinden şu şekilde oluyor , Derece*(pi/180).

Fark eden birşey olmaz.

a = lambda x :(math.sin(x * math.pi / 180)**2)/(math.cos(x * math.pi / 180)**2)
from math import cos, radians, pi
cos(radians(0)) == cos(0 * pi / 180)
# True

Sizin farklı sonuç aldığınız kodlarla üst sınır 10 olmaz ama. Pi 180 değil.

from math import pi
pi * 10 / 180 != 10
# True
pi * 10 / 180 == 0.17453292519943295
# True

Açı söz konusu olduğunda, cos(radians(açı)) yerine cos(açı * pi / 180) yazabilirsiniz. Ama integralin üst sınırını belirlerken 10 * pi / 180 yazarsanız, üst sınırınız 10 olmaz, 0.17453292519943295 olur.

1 Beğeni

Bir sorun goremedim.

f = quad... yerine f = lambda: quad... diyip f yerine f() kullanmak ilginc olmus ama bir seyi degistirmez.

Wolfram alpha baska bir cevap veriyor: https://www.wolframalpha.com/input/?i=integral+of+tan^2(x)+from+0+degrees+to+10+degrees

1 Beğeni

Tamam iste, burada trade-off var. “Garantiye almak” mi istiyorsun, “fonksiyonun islem suresini kisaltmak” mi istiyorsun.

Kodda tanx - x gibi bir sey goremedim, sadece dogru argumanlarla cagrildiginda ZeroDivisionError verecek bir kod var.

Ameleliksizli cozum bu is icin tasarlanmis, test edilmis bir kutuphane kullanmak :slight_smile: Birkac alternatifi @dildeolupbiten denemis zaten, super.

Wolfram Alpha da oyle diyor (bkz. yukaridaki cevap).

1 Beğeni

Evet, orada gerekmediği halde lambda kullanmışım. Genelde, a, b ve c sabitleri için lambda ifadesini kullanıyordum ama o fonksiyonda zaten böyle sabit değerler yok, yani lambda kullanılmasa da olurdu.

Evet, hesaplamayı gördüm, farklı bir sonuç üretiyor. Sebebi de fonksiyonun içindeki x açı değerinin radians(x) şeklinde yazılmaması ve argüman olarak verilen b değerinin de 10 yerine, radians(10) şeklinde yazılması.

Mesela aşağıdaki kodları çalıştırdığımızda;

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from numpy import tan, radians
from scipy.integrate import quad

integrand = lambda x: tan(x) ** 2

f = quad(func=integrand, a=0, b=radians(10))[0]

print(f)

Elde edeceğimiz cevap şu:

0.0017940555090320157

Aşağıdaki kodları çalıştırdığımızda ise,

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from numpy import tan, radians
from scipy.integrate import quad

integrand = lambda x: tan(radians(x)) ** 2

f = quad(func=integrand, a=0, b=10)[0]

print(f)

Elde edeceğimiz sonuç şu:

0.10279180887972904

İntegralin cevabı tan(x) - x.

tan(radians(10)) - radians(10)
# 0.0017940555090320276 sayısını verir.

O halde, benim izlediğim yöntem yanlış oluyor. Demek ki integralini almaya calistigimiz fonksiyonda değil alt ve üst limitlerde radians’i kullanmak gerekiyor.

Edit: bir yanlışlık yok, her iki yöntem de geçerli.

Ikisi de ayni fonksiyon, biri radyan digeri ise dereceyle calisiyor.

Sonucu radyan olarak almak istiyorsak, evet. Oteki turlu derece olarak aliyoruz.

Cevaplarin birbirine orani τ/360° (π/180°).

2 Beğeni

@aib

Haklısınız. :relaxed:

radians(0.10279180887972904) == 0.0017940555090320157