logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[C] Jak poprawić obliczenia logarytmu naturalnego w C bez biblioteki math.h?

poswiatex1 09 Kwi 2009 00:17 2208 6
REKLAMA
  • #1 6391377
    poswiatex1
    Poziom 12  
    Posty: 57
    Pomógł: 1
    Witam, mam następujący problem...
    Chciałem napisać program który będzie mi liczył logarytm naturalny, wiem że w bibliotece math.h jest dostępna, ale właśnie chodzi mi o samodzielne napisanie. Oto kod:
    
    #include <stdio.h>
    #include <math.h>
    
     float ln(float x)
     {
           float wynik = 0;
           int n;
           
           x = x-1;     //Wg, szeregu Maclaurina, (x-1) podnosimy do potegi .
           for (n=1; n<20; n++)            // n<20  20 ustawilem "poprostu"
           {wynik = wynik + pow(x,n)/n;  
           wynik = wynik - pow(x,n)/n;}     //wg wzoru raz jest - a raz +
    
           return wynik;
     }
    
    int main()
    {
        float a, wynik;
        
        printf("Podaj liczbe: ");
        while(scanf("%f", &a) == 1)
        {
    
        printf("ln(%f) = %f\n", a, ln(a));    //Moja straszna funkcja
        printf("log(%f) = %f\n", a, log(a));  //Wyswietlam tu wynik prawidlowy
        }
    
        system("pause");
    }


    No i różnie próbowałem to zrobić, ale ani razu jeszcze nie udało mi się zbliżyć do prawidłowych wartości, proszę o pomoc co mam źle zapisane ?

    Pewnie wszystko znając moje podejscie "dookola" ;-)

    Pozdrawiam,
    Poswiatex1
  • REKLAMA
  • Pomocny post
    #2 6391457
    Demoman
    Poziom 17  
    Posty: 134
    Pomógł: 31
    Ocena: 3
    Ciągle dodajesz i odejmujesz to samo, bo n w pętli Ci się nie zmienia.

    W miarę działający kawek kodu:
     float ln(float x)
     {
           float wynik = 0;
           int n = 1;
           
           x = x-1;
           while (n < 20)  
           {
    		   wynik += pow(x,n)/n; 
    		   ++n;
    		   wynik -= pow(x,n)/n;
    		   ++n;
    	   }
    
           return wynik;
     }
  • REKLAMA
  • #3 6391467
    poswiatex1
    Poziom 12  
    Posty: 57
    Pomógł: 1
    Faktycznie, nie zauważyłem że brakuje mi w kodzie jednego n++, spostrzegawczość o tej godzinie to nie jest moja najlepsza strona ;-)

    Wielkie dzięki i pozdrawiam!

    EDIT:

    Chciałem to z pętli na rekurencję przerobić jeszcze, i ponownie mam problem, bo znów wyskakują dziwne liczby:

    
     float ln(float x)
     {
           int n = 1;
           n += 1;
           return pow(x - 1,n - 1)/n - pow(x - 1,n)/n;
           n += 1;
     }


    Proszę o pomoc, co mam tym razem "skwaszone"?
  • REKLAMA
  • #4 6391514
    Demoman
    Poziom 17  
    Posty: 134
    Pomógł: 31
    Ocena: 3
    To znaczy jaką rekurencję?

    Nie widzę tu niczego rekurencyjnego.

    Jest jeden możliwy błąd w tym kawałku kodu: ostatnie n+= 1 nie wykona się, bo wcześniej wychodzisz z funkcji.

    Poprzedni wzór nie bardzo nadaje się na rekurencje. To znaczy lepiej go implementować iteracyjnie tak jak miałeś wcześniej.
  • REKLAMA
  • #5 6393030
    poswiatex1
    Poziom 12  
    Posty: 57
    Pomógł: 1
    Znaczy, w tym kodzie w return odwoływałem się do mojej funkcji "ln" ale skopiowałem nie z tej wersji kod ;-) mój błąd, będę w domu to wkleję ten odpowiedni kod.
    Domyślam się że lepiej zapętlić, ale chciałem jakimś innym sposobem zrobić, mam możliwość zrobienia tego jeszcze 3 sposobem ale nie wiem na czym on polega, a jak on się nazywam też sobie w domu zapisałem ;-)

    EDIT:

    Faktycznie nie wychodziło mi zrobienie tego programu z wykorzystaniem rekurencji. Bardzo Was proszę może ktoś mi podrzuci pomysł ?
    Nie oczekuję gotowców, wolę jakąś pomoc, żebym po części mógł sam mieć w to wkład. (jeśli się w ogóle da zrobić w takiej wersji)

    Albo mam możliwość napisania ln "metodą bezpośrednią", nie rozumiem, nie wiem co kryje się pod tym wyrażeniem.

    Pozdrawiam
    Poswiatex1 ;-)
  • Pomocny post
    #6 6394418
    Demoman
    Poziom 17  
    Posty: 134
    Pomógł: 31
    Ocena: 3
    Rekurencyjnie musiałbyś zrobić 2 funkcje:

    float ln(float x);
    float ln_rek(float x, int poziom);


    Wystarczyła by nawet jedna, ale dla pewności, że user zawsze zacznie od poziomu 1 lepiej zrobić dwie.

    Pierwsza wywołuje drugą rekurencyjnie.

    Kawałek kodu:

    float ln(float x)
    {
       x = x - 1.0;
    
       return ln_rek(x, 1);
    }
    
    float ln_rek(float x, int poziom)
    {
       float wyn;
    
       if(poziom > 20)
          return 0.0;
    
       wyn = (pow(x,poziom)/poziom) - (pow(x, poziom+1)/(poziom+1));
    
       return wyn + ln_rek(x, poziom + 2);
    }
  • #7 6394582
    poswiatex1
    Poziom 12  
    Posty: 57
    Pomógł: 1
    Wielkie dzięki za pomoc!

    Odkąd zacząłem zadawać pytania na tym forum, tak przyspieszyło się zdobywanie przeze mnie wiedzy nt. C ;-)

    Pozdrawiam
    Poswiatex1 !

Podsumowanie tematu

✨ Dyskusja dotyczy implementacji funkcji obliczającej logarytm naturalny (ln) w języku C bez użycia biblioteki math.h. Pierwotny kod opierał się na rozwinięciu szeregu Maclaurina, jednak zawierał błąd polegający na braku odpowiedniego inkrementowania zmiennej sterującej pętlą, co skutkowało dodawaniem i odejmowaniem tych samych wartości. Poprawiona wersja kodu stosuje naprzemienne dodawanie i odejmowanie kolejnych wyrazów szeregu z prawidłowym zwiększaniem indeksu. Próby implementacji rekurencyjnej napotkały trudności, ponieważ oryginalny wzór nie jest naturalnie rekurencyjny. Zaproponowano rozwiązanie z dwiema funkcjami: jedną wywołującą rekurencyjnie drugą, która sumuje wyrazy szeregu z krokiem co dwa indeksy, co pozwala na poprawne obliczenie ln(x) rekurencyjnie. Dyskusja podkreśla znaczenie poprawnego zarządzania indeksami i strukturą funkcji w implementacji matematycznych szeregów w C.
Podsumowanie wygenerowane przez AI na podstawie treści dyskusji.
REKLAMA