symbol Newtona błąd wykonania

0

Cześć.

Napisałem taki program który ma obliczać wartość symbolu Newtona:

#include <iostream> 
using namespace std; 

unsigned long long int silnia(unsigned long long int h) 
{ 
    switch (h) 
    { 
           case 1: 
                return 1; 
                break; 
           default: 
                return h * silnia(h-1);
    } 
} 
int main() 
{ 
    unsigned long long int n,k,i,t,j,sume=1,mian;
    cin>>t;
    for(i=0; i<t; i++)
    {
      cin>>n>>k;
      sume=1;
      for(j=(n-k+1); j<=n; j++)
                 sume*=j;
    if(n==k) cout<<1;
    else
     {
      mian=silnia(k);
      cout<<sume/mian;
     }
    }
    return 0;
}  

Po sprawdzeniu takiego zestaw:
1
32 16
wyświetla nieprawidłowy wynik. Hmm nie wiem w czym problem.

0

long long przechowa ci maksymalnie wartość 20! (albo 21!, nie pamiętam).
Pytanie tylko po co chcesz to tak obliczać, skoro można to wcześniej sobie poskracać. Swoją drogą ciekawe jest że tutaj:

for(j=(n-k+1); j<=n; j++)
  sume*=j;

umiesz liczyć iteracyjne silnie, a w innym miejscu już nie...

0

I właśnie już tutaj mu się wywala dla 32 po 16. 171819*...*32 nie mieści się w unsigned long long int.

0

Nie mam pomysłu jak zmodyfikować kod, zeby działał poprawnie...?

0

To nie problem z kodem (no moze prócz tej rekurencji...) a z matematyką.

0

Zmodyfikowałem kod:

 
int main() 
{ 
    unsigned long long int n,k,i,t,j,sume=1,mian=1;
    cin>>t;
    for(i=0; i<t; i++)
    {
      cin>>n>>k;
      sume=1;
      for(j=(n-k+1); j<=n; j++)
                 sume*=j;
    if(n==k) cout<<1;
    else
     {
      mian=1;
      for(j=1; j<=k; j++)
              mian*=j;
      cout<<sume/mian;
     }
    }
    return 0;
} 

Jednak wynik dalej niepoprawny :/

0

Bo nie umiesz czytać. Napisaliśmy ci wyraźnie że problem nie jest z kodem, a z matematyką. Podpowiem ci:
gdybyś mial policzyc na kartce działanie
(23456789)/(234567*8)
to czy mnożyłbyś to wszystko żeby uzyskać postać:
362880/40320
i dopiero potem podzielic i dostać wynik 9?
Nie, użyłbyś mózgu żeby sobie to poskracać. Tutaj jest tak samo. Przy czym nie jest to takie trywialne.

0

Tu chyba ktoś inny ma problemy z czytaniem...
Skróciłem w programie co umiałem, tak że silnia jest liczona tylko dla mian.

0

@autor poczytaj sobie lepiej o zakresach typów danych w c++. Sprawdź jaką maksymalną liczbę można przypisać do unsigned long long, a potem policz sobie 20! czy tam 21! i porównaj z maksymalną wartością dla danego typu. Gdy porównasz zrozumiesz swój problem. A co się dzieje gdy przekroczysz wartość maksymalną (albo minimalną) typu? To samo co by się stało z licznikiem samochodowym gdyby ci się "skończył" ... przekręci ci się.

0

Już Ci Shalom napisał, masz kłopoty z rachunkami (do matematyki to jednak jeszcze daleko). Nigdzie, ani w liczniku, ani w mianowniku nie powinieneś liczyć silni.
Przykładowo dla danych n=1000 k=999, obliczenia powinny wyglądać tak: ((1000/2)*999)/1

0

Późną porą łatwo o pomyłkę, dla n=1000, k=999 powinno być ((1000/1)*999)/2. Dla n=1000, k=998 powinno być (((1000/1)*999)/2)*998)/3. Nawiasy napisałem żeby zaznaczyć kolejność działań: naprzemiennie dzielenie i mnożenie.
Korzystając z 8-bajtowego typu liczbowego policzysz wtedy poprawnie wszystkie współczynniki dla n<=61.

0

Masz to zrobić tak:
masz taki ułamek: newton\left(16,20\right)=\frac{17\cdot 18\cdot 19\cdot 20}{1\cdot 2\cdot 3\cdot 4}
A to można sprytnie pogrupować:
\frac{17\cdot 18\cdot 19\cdot 20}{1\cdot 2\cdot 3\cdot 4}= \left(\left(\left(\frac{20}{1}\cdot\frac{19}{2}\right)\cdot\frac{18}{3}\right)\cdot\frac{17}{4}\right)
Zwróć uwagę, że każdy nawias reprezentuje liczbę całkowitą.

0

Dzięki za pomoc! :)

Ale na tym nie koniec...
Zmodyfikowałem program do takiej postaci:

 
int main() 
{ 
    long long n,k,i,t,j,sume;
    cin>>t;
    for(i=0; i<t; i++)
    {
      cin>>n>>k;
      sume=1;
      for(j=0; j<k; j++)
               sume=(sume*(n-j))/(j+1);
      cout<<sume<<endl;
    }
    return 0;
} 

Podczas kompilacji wyświetla mi błędna odpowiedź... w czym problem?? :/

0

Pewnie i tak wykraczasz poza zakres. Po wczytaniu n i k dodaj jeszcze:

if (k > n - k)
    k = n - k;

I porównaj wyniki dla np. n = 1000; k = 999

0

Zaakceptowano! Thx :)

0

Napisałem ten sam program, ale w języku C

#include <stdio.h> 

main() 
{ 
    long long sume;
    short n,k,i,t,j;
    scanf("%i",&t);
    for(i=0; i<t; i++)
    {
      scanf("%d%d",&n,&k);
      if (k>n-k) k=n-k;
      sume=1;
      for(j=0; j<k; j++)
               sume=(sume*(n-j))/(j+1);
      printf("%d\n",sume);
    }
    return 0;
}  

Jestem zielony z programowania w C, dlatego proszę o poprawienie kodu, żeby działał poprawnie... thx!

1 użytkowników online, w tym zalogowanych: 0, gości: 1