• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Program do obliczania wartości klepaków po wadze - co zrobić, żeby wynik był dokładny?

Object Storage Arubacloud
0 głosów
500 wizyt
pytanie zadane 5 listopada 2016 w C i C++ przez Werlock Użytkownik (580 p.)
Napisałem krótki program do obliczania wartości klepaków po podaniu ich wagi. Wzór jest taki: waga wszystkich monet/1,64+2,13+2,59*1+2+5

Czyli waga/wagę 1gr+2gr+5gr*1gr+2gr+5gr. I to działa, ale przy większych liczbach pojawia się kłopot - mianowicie wynik staje się zawyżony. Moim zdaniem chodzi o rozwinięcia dziesiętne w czasie dzielenia i mnożenia i o zaokrąglanie. Co zrobić, żeby wynik był dokładny?

Kodu nie wklejam, bo jestem poza domem.

 

Z góry dziękuję za pomoc koledzy.

2 odpowiedzi

0 głosów
odpowiedź 5 listopada 2016 przez niezalogowany
edycja 30 sierpnia 2017
 
Najlepsza

Troszkę się zastanawiałem jak można znaleźć Twoją wagę. Doszedłem do wniosku, że jest to jednoznacznie nie możliwe. Z samej matematyki. Analizując:

Mamy wartości monet:

w1 = 1gr 
w2 = 2gr
w3 = 5gr

Mamy masy monet:

m1=1.64
m2=2.13
m3=2.59

Mamy ilości danych monet:(przykladowo)

n1 = 25
n2 = 7
n3 = 18

Zatem z nich wyliczyliśmy masę monet:
waga = n1*m1 + n2*m2 + n3*m3

I z tej masy chcemy przejść do całkowitej wartości monet:
kwota = n1*w1 + n2*w2 + n3*w3

Nie można tego jednoznacznie wyliczyć za pomocą dodawania/odejmowania/mnożenia/dzielenia ... Chociaż rozumiem ideę wzoru, który miałeś - tylko problem w tym, że jest on wynikiem błędu matematycznego. Zapisując szeregami:

waga = suma(n m)  // nie ma na tym forum LaTeXu więc ciężko będzie :D
kwota = suma(n w)

Zasadniczy błąd polegał chyba na zamienieniu sumy iloczynów ilości i mas na dwie sumy osobno ilości i osobno mas.

waga = suma(n)*suma(m) 
 // co jest zdecydowanie błędne bo waga w tym momencie ma po wymnożeniu 9 elementów
kwota = suma(n)*suma(w)
więc suma(n) = waga/suma(m)

Wszystko doprowadziło do wzoru:
kwota = (waga*suma(w) ) / suma(m)

Czyli do:

kwota =  waga wszystkich monet*(1+2+5)/1,64+2,13+2,59

Jednak możliwe jest znalezienie numerycznie wszystkich możliwych kombinacji liniowych! Wystarczy zrobić kilka pętli dobierających różne ilości monet. Jeżeli ich łączna masa będzie równa wadze monet to spełniają one nasze warunki. Przykładowy kod:

#include <iostream>

using namespace std;

int main()
{
    double waga_wszystkich=0;
    double wartosc_wszystkich=0;
    double wartosc_wszystkich_z_wagi=0;
    double grosze[] = {1, 2, 5};
    double mas[] = {1.64, 2.13, 2.59};
    double ilosc[] = {25, 7, 18};

    /*
    for(int i=0; i<3; i++) cin>>ilosc[i];
    */

    for(int i=0; i<3; i++)
    {
        waga_wszystkich+=ilosc[i]*mas[i];
    }

    cout<<"Drobniaki waga: "<< waga_wszystkich <<endl;

    for(int i=0; i<3; i++)
    {
        wartosc_wszystkich+= ilosc[i]*grosze[i];
    }

    cout<<"Wartosc wszystkich: "<<wartosc_wszystkich<<endl;

    /* Stary wzor */
    wartosc_wszystkich_z_wagi = waga_wszystkich*8/(1.64+ 2.13+ 2.59);
    cout<<"Wartosc wszystkich z wagi (stary wzor): "<<wartosc_wszystkich_z_wagi<<endl;

    /* Wszystkie możliwe wartosci */
    cout<<"Wartosc z mozliwej wagi i ilosc danych monet:"<<endl;

    for(double i=0; i<waga_wszystkich; i++)
        for(double j=0; j<waga_wszystkich; j++)
            for(double k=0; k<waga_wszystkich; k++)
            {
                double nibymasa = mas[0]*i+mas[1]*j+mas[2]*k;

                if(nibymasa==waga_wszystkich)
                {
                    cout<<"Waga: "<<nibymasa<<" - Kombinacja: \n";
                    cout<<grosze[0]*i+grosze[1]*j+grosze[2]*k<<"\t----->\t";
                    cout<<grosze[0]<<"gr - "<<i<<",\t"<<grosze[1]<<"gr - "<<j<<",\t"<<grosze[2]<<"gr - "<<k<<"\n\n";
                }
            }


    return false;
}
komentarz 5 listopada 2016 przez niezalogowany
edycja 5 listopada 2016
To, że ten stary wzór jest czasem poprawny gdy ilości nie różną się strasznie np 10 11 10, 4 5 4, 64 66 64.... to wszystko z winy matematyki :D

EDIT: Gdy ilości są takie same (ewentualnie podobne wtedy będzie jakiś mały błąd) wzór na kwotę można uprościć do tego wzoru co miałeś. I dlatego był sprawiał wrażenie poprawnego.
komentarz 5 listopada 2016 przez niezalogowany
edycja 30 sierpnia 2017

Zauważyłem jeszcze jeden problem. Czasami mamy też minimalne błędy wynikające z przybliżenia zmiennej double i wtedy nie zachodzi równość. Wtedy trzeba sprawdzać jakie rozwiązania są blisko naszego które chcemy.

Dla ilości monet:

double ilosc[] = {19, 18, 21};

Nie zostanie znalezione żadne rozwiązanie. Więc trzeba będzie zmienić nasze pętle na:

    /* Wartosci bliskie oczekiwanej */
    double nmin = 0.001;

    for(double i=0; i<waga_wszystkich; i++)
        for(double j=0; j<waga_wszystkich; j++)
            for(double k=0; k<waga_wszystkich; k++)
            {
                double nibymasa = mas[0]*i+mas[1]*j+mas[2]*k;

                if(nibymasa<(waga_wszystkich+nmin) && nibymasa>(waga_wszystkich-nmin))
                {
                    cout<<"Waga: "<<nibymasa<<" - Kombinacja: \n";
                    cout<<grosze[0]*i+grosze[1]*j+grosze[2]*k<<"\t----->\t";
                    cout<<grosze[0]<<"gr - "<<i<<",\t"<<grosze[1]<<"gr - "<<j<<",\t"<<grosze[2]<<"gr - "<<k<<"\n\n";
                }
            }
komentarz 6 listopada 2016 przez Werlock Użytkownik (580 p.)
Krótko mówiąc: dzięki stary! Resztę epitetów i pochwał sam sobie wykreuj, bo się zdecydowanie należą :) Dziękuję .
0 głosów
odpowiedź 5 listopada 2016 przez Evelek Nałogowiec (28,960 p.)
Nie widzę kodu, może ustaw wszystkie typy zmiennych na double.
komentarz 5 listopada 2016 przez Werlock Użytkownik (580 p.)
Pozwolę sobie z pamięci przytoczyć istotny fragment:

float waga = x.xx;

cout<<waga/(1,64+2,13+2,59)*(1+2+5);

Pozdrawiam.
komentarz 5 listopada 2016 przez niezalogowany
Mianownik weź w nawias. Inaczej najpierw będzie wykonywane działanie "waga/(1,64+2,13+2,59)" a dopiero później wartość ta zostanie przemnożona przez (1+2+5).
komentarz 5 listopada 2016 przez Werlock Użytkownik (580 p.)
Nie do końca zrozumiałem :/ Mógłbyś mi zapisać ten wzór z Twoją poprawką? Bo mój generalnie działa tylko im większą wagę podasz, tym bardziej wynik będzie niedokładny.
komentarz 5 listopada 2016 przez Evelek Nałogowiec (28,960 p.)
cout<<(waga)/((1,64+2,13+2,59)*(1+2+5));
komentarz 5 listopada 2016 przez Evelek Nałogowiec (28,960 p.)
Typ zmiennej double mieści więcej cyfr niż float, może to też jest przyczyną.
komentarz 5 listopada 2016 przez Werlock Użytkownik (580 p.)
Dziękuję Wam. Jak wrócę do domu to przetestuję i może powstanie coś użytecznego. Jeśli chodzi o float i double to najpierw miałem double, a potem dałem floata i wynik był ten sam :/
komentarz 5 listopada 2016 przez niezalogowany
Tutaj nie będzie widać żadnej różnicy między float, a double. Znaczenie ma kolejność działań. Co to znaczy, że działa? To, że wypisuje wynik nie znaczy, że coś jest prawidłowe. Jak weźmiesz mianownik w nawias o tak:

cout<<waga/((1,64+2,13+2,59)*(1+2+5));

To masz zupełnie co innego. Wszystkie wyniki będą mniejsze, bo przedtem mnożyłeś razy 8, a teraz dzielisz. Wynik zmniejszy się teraz 64-krotnie.
komentarz 5 listopada 2016 przez Werlock Użytkownik (580 p.)
Hmmm, sprawdziłem to wykonując po kolei obliczenia i raczej coś tu nie gra. Być może źle się wyraziłem, więc dam przykład z liczbami:

1 gr waży 1,64g

2 gr ważą 2,13g

5 gr waży 2,59g

Niech waga = 18*2,59+7*2,13+25*1,64 = 102.53.

I teraz wg starego wzoru jest: 102.53/(1.64+2.13+2.59)*8=128.9685534, czyli 102.53 g klepaków to prawie 129 gr.

Faktyczny wynik powinien wynosić:18*5+7*2+25*1=129gr - no, akurat teraz wyszło dobrze.

Ale inne liczby dajmy:

waga=21*(2.59+18*2.13+19*1.64)=123.89;

I znowu wg starego wzoru: 123.89/(1.64+2.13+2.59)*8=155.8364779.

Powinno wyjść: 21*5+18*2+19*1=142gr.

Więc wynik się nieco zawyżył. Gdybym wziął mianownik w nawias to wyszłoby coś nielogicznego: przecież 123.89 g klepaków nie może mieć wartości mniejszej niż 1 grosz. I tu jest ten problem, co zrobić, żeby ten wynik się tak nie zawyżał i program mógł posłużyć do obliczenia ile groszy ma x gram klepaków (1gr, 2 gr i 5 gr).

 

Pozdrawiam i dziękuję za zainteresowanie moim problemem.
komentarz 5 listopada 2016 przez niezalogowany
Skąd masz ten stary wzór? Wydaje mi się, że miałeś po prostu szczęśliwy przypadek, że wyszło Ci dobrze. To wygląda na coś bardziej skomplikowanego...

Podobne pytania

0 głosów
1 odpowiedź 80 wizyt
0 głosów
1 odpowiedź 320 wizyt
pytanie zadane 8 lutego 2023 w JavaScript przez niezalogowany
0 głosów
1 odpowiedź 123 wizyt

92,576 zapytań

141,426 odpowiedzi

319,652 komentarzy

61,961 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...