całkowitych a dokładność

Witam,

Trochę już minęło czasu od zajęć z metod numerycznych... więc jak najlepiej wykonać taką operację:

Mam liczbę całkowitą która maksymalnie osiąga wartość 2^13, ale muszę ją pomnożyć przez niecałkowity współczynnik, który będzie wynosił około 0,3. Zmienne wykorzystywane w obliczeniach są 16 bitowe (nie mam tyle mocy obliczeniowej żeby przejść na liczby zmiennoprzecinkowe). Ponieważ 0,3 to to samo co 3/10, to mogę sobie rozbić moje działanie na mnożenie przez 3 i dzielenie bez reszty przez 10.

Pytanie - jaka kolejność zapewnia większą dokładność? Najpierw mnożyć czy lepiej najpierw dzielić? Co w przypadku gdy mój współczynnik wyniesie np.

0,32 - wykonanie jako pierwszego mnożenia przez 32 (a potem dzielenia przez 100) da mi pośredni wynik większy niż zakres mojej 16-bitowej zmiennej.
Reply to
Jakub Rakus
Loading thread data ...

Jakub Rakus snipped-for-privacy@op.pl napisał(a):

Najpierw mnożyć, żebyś błędu zaokrąglenia nie mnożył.

Mnóż przez 8 a potem dziel przez 25.

Reply to
Grzegorz Niemirowski

Dnia Wed, 19 Sep 2012 19:25:51 +0200, od Jakub Rakus snipped-for-privacy@op.pl nadeszla wiadomosc:

0,32 = 3/10 + 2/100

Nie musisz mnożyć przez więcej niż 9 ;-)

Reply to
Slawek Maculewicz

Faktycznie, wykonałem wcześniej kilka obliczeń "na kartce" na losowo wymyślonych liczbach i tak też mi się wydawało.

Też nad tym myślałem, tylko jeszcze nie bardzo wiem jak programowo rozwiązać zamianę liczby z zakresu 0.20-0.50 na najbliższy jej ułamek zwykły o liczniku nie większym od 8. Mój współczynnik będzie najpierw ustawiany podczas procesu automatycznej kalibracji - całość bowiem dotyczy przeliczenia wartości uzyskanej z przetwornika A/C.

Reply to
Jakub Rakus

Użytkownik "Jakub Rakus" napisał w wiadomości grup

Chyba nie masz watpliwosci, ze np 4/10 = 0, 0*3= 0 ?

O to to to :-)

Jesli masz dostep do assemblera/ukladu mnozacego, to nie mnozysz przez

0.32, ale np przez 20972. Tylko ze robisz mnozenie z wynikiem 32-bit, z ktorego wybierasz dalej tylko starsze slowo. Bo 65536*0.32=20971.52

jesli te wspolczynniki sa tego rzedu, to mozesz rozlozyc

0.32=0.0101001...b a wiec x*0.32 = x>>2 + x>>4 + x>>7 ...

J.

Reply to
J.F

W dniu 2012-09-19 19:25, Jakub Rakus pisze:

Nie napisałeś w jakim języku chcesz pisać. Jeśli w c to użyj double. Jeśli w asm to musisz na potrzeby tego mnożenia napisać własną procedurkę mnożenia dwóch 16 bitowych z wynikiem na np 24 czy 32 bitach. Kolejność działań to oczywiście najpierw mnożenie potem dzielenie.

Reply to
Mario

Am 19.09.2012 22:32, schrieb Mario:

Przecież pisze wyraźnie, że nie ma mocy obliczeniowej na floaty, a ty mu z double wyskakujesz.

Osobiście robię takie rzeczy tak, by jak najmniej stracić i szybko liczyć. Czyli ułamek wyrazić jako ułamek dwójkowy, czyli na przykład twoje 0.32 jako 41/128. Następnie mnożę dwie liczby 16to bitowe z wynikiem 32 bity i przesuwam o n = log2(128) czyli 7 w prawo. Na większości procesorów działa bez problemu. W przypadku bardziej "krzywych" współczynników rozkładam na pasujące czynniki, które są później sumowane. Jak procek ma jednostkę mnożącą, to nie trzeba przesuwać i można od razu mnożyć, ale mianownik dwójkowy jest zawsze wygodniejszy.

Waldek

Reply to
Waldemar Krzok

W dniu 2012-09-20 09:49, Waldemar Krzok pisze:

Sorki miało być long.

Zdaje się, że pytający właśnie nie wie jak zrobić żeby mieć wynik 32 bitowy.

Reply to
Mario

Będę marudził, ale nie chce liczb 32-bitowych :P więc to odpada.

Ale za to to rozwiązanie mi się podoba :) Przeliczenie współczynnika na liczbę 8 czy nawet 16-bitową i tak będzie wykonane tylko raz na jakiś czas podczas procedury kalibracji, a trochę przesunięć bitowych nie zeżre mi dużo cennego czasu i kodu programu.

Reply to
Jakub Rakus

Masz 8 bitowy procesor? To nadal mnożenie 2 16 bitowych w 32 bitową to tylko 4 mnożenia. A przesuwanie bitowe liczb dłuzszych niż rejestr też trochę kosztuje.

W złym wypadku masz 12 tych działań.

Trochę teraz pogdybam. Jeśli jednak masz procek 16 bitowy, możesz pomysł J.F. nieco pożyłować. x ma być 12 bitowe (mówiłeś, że maks to 2^13. Zakładam, że ograniczenie się do 2^13-1 nie jest problemem) Mamy więc całe 3 bity, możemy mnożyć przez 111_b i będzie ok.

(x*a_1)>>3 + (x*a_2)>>6 + (x*a_3)>>9 + (x*a_4)>>12 + (x*a_5)>>15

gdzie a_i to kolejne trójki bitów Twojego mnożnika.

Jeśli mnożnik jest w okolicach 0.3, dokładniej jest <0.5 to od razu (x*a_1)>>4 + (x*a_2)>>7 + (x*a_3)>>10 + (x*a_4)>>13 + (x*a_5)>>16

Czyli samo (x*a_1)>>4 + (x*a_2)>>7 + (x*a_3)>>10 + (x*a_4)>>13 bo (x*a_5) jest 16 bitowe, więc przesunięcie go zjada.

pzdr bartekltg

Reply to
bartekltg

Jak nie zmiennoprzecinkowe, to może stałoprzecinkowe? O ile dobrze zrozumiałem z innych postów, to kalibracja może być złożona obliczeniowo, natomiast aplikowanie współczynnika ma być szybkie, proste i dokładne. Ja bym to zrobił tak: dany współczynnik (zakładając, że jest mniejszy od

1) zapisał jako liczbę stałoprzecinkową np. 0.16 (tzn 0 bitów liczby całkowitej i 16 bitów po przecinku) lub jak nie jest potrzebna aż taka dokładność, to 0.8. Potem w zasadzie tylko mnożysz daną przez ten współczynnik (mnożenie 16bitx16bit lub 16bitx8bit), wywalasz wszystko 'po przecinku' do kosza (czyli bierzesz za wynik 2 najstarsze bajty) i tyle. Jeżeli masz w procku hardwarowe mnożenie, to będzie bardzo szybko. Natomiast przy kalibracji możesz się trochę pogimnastykować, żeby wyliczyć ten współczynnik (też na stałoprzecinkowych, pamiętając o zakresach liczb).

Podstawowym błędem w rozumowaniu jest przyjęcie, że współczynnik bedziesz trzymał w postaci dziesiętnej.

Pozdrawiam

Marek

Reply to
Marek Wodzinski

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.