eGospodarka.pl
eGospodarka.pl poleca

eGospodarka.plGrupypl.comp.programmingjak posortować czynniki › Re: jak posortować czynniki
  • X-Received: by 10.157.6.102 with SMTP id 93mr711472otn.11.1476366084912; Thu, 13 Oct
    2016 06:41:24 -0700 (PDT)
    X-Received: by 10.157.6.102 with SMTP id 93mr711472otn.11.1476366084912; Thu, 13 Oct
    2016 06:41:24 -0700 (PDT)
    Path: news-archive.icm.edu.pl!agh.edu.pl!news.agh.edu.pl!newsfeed2.atman.pl!newsfeed.
    atman.pl!news.nask.pl!news.nask.org.pl!news.unit0.net!news.glorb.com!g45no56546
    5qte.1!news-out.google.com!w143ni1807itb.0!nntp.google.com!o19no938692ito.0!pos
    tnews.google.com!glegroupsg2000goo.googlegroups.com!not-for-mail
    Newsgroups: pl.comp.programming
    Date: Thu, 13 Oct 2016 06:41:24 -0700 (PDT)
    In-Reply-To: <ntm5rn$3p5$1@node1.news.atman.pl>
    Complaints-To: g...@g...com
    Injection-Info: glegroupsg2000goo.googlegroups.com; posting-host=77.254.35.87;
    posting-account=xjvq9QoAAAATMPC2X3btlHd_LkaJo_rj
    NNTP-Posting-Host: 77.254.35.87
    References: <1...@g...com>
    <ntlp6e$2bl$1@node2.news.atman.pl>
    <a...@g...com>
    <ntlujd$7ku$1@node2.news.atman.pl>
    <3...@g...com>
    <ntm5rn$3p5$1@node1.news.atman.pl>
    User-Agent: G2/1.0
    MIME-Version: 1.0
    Message-ID: <d...@g...com>
    Subject: Re: jak posortować czynniki
    From: "M.M." <m...@g...com>
    Injection-Date: Thu, 13 Oct 2016 13:41:24 +0000
    Content-Type: text/plain; charset=UTF-8
    Content-Transfer-Encoding: quoted-printable
    Xref: news-archive.icm.edu.pl pl.comp.programming:209925
    [ ukryj nagłówki ]

    On Wednesday, October 12, 2016 at 10:19:04 PM UTC+2, bartekltg wrote:
    > On 12.10.2016 20:59, M.M. wrote:
    > > On Wednesday, October 12, 2016 at 8:15:10 PM UTC+2, bartekltg wrote:
    > >> On 12.10.2016 19:55, M.M. wrote:
    > >>> On Wednesday, October 12, 2016 at 6:42:55 PM UTC+2, bartekltg wrote:
    > >>>> Nie ma znaczenia.
    > >>>> Mnożysz mantysy, które zawsze są w przedziale [0.5,1)
    > >>>> cechy dodajesz stałoprzecinkowo.
    > >>>> ["Ty w sensie komputer jak mnożysz zmienne float/double",
    > >>>> nie trzeba nic ręcznie poprawiać].
    > >>>
    > >>> Fajny sposób.
    > >>
    > >> Po to był nawias kwadratwy.
    > >> To nie jest sposób.
    > >> Tak komputer po prostu mnoży liczby zmiennoprzecinkowe.
    > >
    > > No tak, ale w C++ (chyba) nie ma instrukcji która wymnoży w ten sposób
    > > więcej niż dwie liczby? Powiedzmy że mamy 10 dużych liczb i 10 małych.
    >
    > A ile liczb chcesz mnożyć?
    >
    > Przeczytaj, jak są zbudowane liczby zmiennoprzecinkowe.
    >
    > Teraz widzisz?
    >
    > Operacja pomnożenia ich po kolei (jedna po drugiej)
    > robi to co opisałem.
    > Mnoży (też po kolei!) mantysy, a cechy się dodają.
    >
    >
    > > Gdy zacznę mnożyć od małych, to pewnie najpierw osiągnę zero, więc
    > > potem mnożenie przez duże liczby da wynik zero.
    >
    > Spodziewasz się przekroczyć 10^-308?
    > Wtedy dopiero wchodzimy w zakres liczb podnormalnych
    > i tracimy.
    > Jak rzeczywisćie masz taki wtedny szereg, to posortuj
    > i jeśli dotychczsowy wynik jest <1, bierz liczbę
    > z "małego" końca, jeśli > 1, bierz z dużego.
    >
    > Wtedy, jeśli wynik mieści się w zakresie,
    > też nie powinieneś tego zakresu przekroczyć.
    >
    >
    > > Dobrze byłoby posortować: raz duża, raz mała, ale to trudne jest.
    >
    > Wystarczy brać z obu końców ;->
    >
    > Ale sortowanie jest kosztowne;-)
    >
    > Jeśli liczby nie są za duże/za małe, wyciagaj co jakiś
    > czas cechę i trzymaj w jakimś int64_t ;-)
    >
    > Wyciaga się tym:
    > http://en.cppreference.com/w/cpp/numeric/math/frexp
    >
    >
    > > Lepiej wyciągnąć po każdym mnożeniu wykładnik sumować w osobnej
    > > zmiennej, a w bieżącym wyniku go zerować. Coś mniej/więcej tak:
    > >
    > > wynik = 1;
    > > E = 0;
    > > tab[N];
    > > for( i=0 ; i<N ; i++ ) {
    > > wynik *= tab[i];
    > > E += wykladnik( wynik );
    > > wynik /= baza ^ wykladnik( wynik );
    > > }
    >
    > 1. Używaj frexp.
    >
    >
    >
    > 2. Naprawdę masz aż tak wielkie liczby? I jednocześnie umiarkowany
    > wynik? Doble trzyma od 10^-308 do 10^308 z taką samą precyzją.
    >
    > Jeśli liczby mają wykłądniki [-10, 10] spokojnie możesz mnożyć
    > po 30 w kupie.
    >
    > [BTW, jeśli to dwumian Newtona, to daje się go rozsądniej obliczać;)]
    >
    >
    >
    > Wracając do błędów. Co prawda mnożenie jest porządne,
    > w przeciwieństwie do dodawania nigdy nie tracimy cyfr
    > znaczacych (uwarunkowanie jest równe 1), to mozę jednak
    > występuje efekt podobny jak widoczny w porównaniu
    > normalnego sumowania i sumowania 'parami'.
    > https://en.wikipedia.org/wiki/Pairwise_summation
    > Można by sprawdzić, czy dla mnożenia też daje lepszy wynik.
    >
    > Z linka zerknij na odnośnik [1]. To chyba o tej pracy wspominałem
    > poprzednio.
    >
    > Prosty test (kod na końcu)
    >
    > Wyniki... niejednoznaczne;-)
    >
    >
    > -2.91802e-13
    > -3.21668e-12
    > 3.16062e-14
    > -5.34369e-14
    >
    > -2.91802e-13
    > -3.21668e-12
    > 1.26974e-13
    > -2.03522e-14
    >
    > Mnożenie parami czasem coś poprawia, czasem nie,
    > Pogarsza znacznie dla ciągu po kolie.
    > Za to losowa kolejność poprawia wynik;-)
    >
    > Elementami ciągu są liczby niewymeirne bliskie jedynce,
    > iloczyn powinien być równy 1, z powodu błędów zaokrągleń
    > na poziomie wyliczania wartośći 'dokaladną' sumę licze
    > zmienną GMP sporej precyzji.
    >
    > w sumie 10^6 elementów, każdy z błędem rządu 10^-16,
    > 10^-13 ma prawo odparować.
    >
    >
    > pzdr
    > bartekltg
    >
    >
    > #include <iostream>
    > #include <random>
    > #include <boost/multiprecision/gmp.hpp>
    > #include <chrono>
    > #include <random>
    > #include <algorithm>
    >
    > template <typename iterator>
    > double recmul(const iterator & first, const iterator & second)
    > {
    > if (second-first == 1 ) return *first;
    > else
    > {
    > auto mid = first + (second-first)/2;
    > return recmul(first, mid)*recmul(mid, second);
    > }
    >
    >
    > }
    >
    >
    > int main()
    > {
    > const int N = 1024*1024;
    > vector <double> tab;
    > tab.reserve(2*N);
    >
    > for (int i=1; i<N;i++)
    > {
    > tab.push_back(sqrt( i/(double)(i+1) ));
    > tab.push_back(sqrt( (i+1)/(double)i ));
    > }
    >
    > boost::multiprecision::mpf_float_1000 MP_wyn=1;
    > for (auto it = begin(tab); it<end(tab); ++it )
    > MP_wyn*=*it;
    >
    >
    >
    > double aku=1.0;
    > for (auto it = begin(tab); it<end(tab); ++it )
    > aku*=*it;
    >
    > cout<< aku-MP_wyn << endl;
    > cout<< recmul(begin(tab),end(tab))-MP_wyn << endl;
    >
    > random_device rd;
    > default_random_engine gen(rd());
    > shuffle(begin(tab),end(tab),gen);
    >
    > aku=1.0;
    > for (auto it = begin(tab); it<end(tab); ++it )
    > aku*=*it;
    >
    >
    > cout<< aku-MP_wyn << endl;
    > cout<< recmul(begin(tab),end(tab))-MP_wyn << endl;
    >
    > return 0;
    >
    > }

    Dzięki za odpowiedź, najbardziej przyda się pomysł
    który mi podsunąłeś, żeby wyciągać eksponenty :)
    Resztę w miarę ogarniam.

    Mam takie liczby do wymnożenia, że przy 80 losowo wybranych
    często pada. Liczby, choć nie służą do wyliczenia dwumianiu
    newtona, to powstają z dużych dodatnich i ujemnych potęg, więc
    mogą po wymnożeniu nawet dać coś w okolicach jedynki. Napisałem
    najpierw podobnie do sortowania. Czynniki mam w kilku wektorach,
    jeśli w jednym mam czynniki duże, to w drugim mam małe, albo
    na odwrót. S skrócie: próbuję wymnożyć przez jedną, potem przez
    drugą i wybieram tę, która daje wynik bliższy jedynce. Po tym
    zabiegu mogę wymnożyć nawet 400 liczb bez problemów z zakresem, a
    nie muszę sortować. Jednak pomysł z przeniesieniem wykładników
    do osobnej zmiennej zapewne będzie najlepszy i szybki.

    Pozdrawiam

Podziel się

Poleć ten post znajomemu poleć

Wydrukuj ten post drukuj


Następne wpisy z tego wątku

Najnowsze wątki z tej grupy


Najnowsze wątki

Szukaj w grupach

Eksperci egospodarka.pl

1 1 1

Wpisz nazwę miasta, dla którego chcesz znaleźć jednostkę ZUS.

Wzory dokumentów

Bezpłatne wzory dokumentów i formularzy.
Wyszukaj i pobierz za darmo: