[size=7]Ovaj post je nastao jer mi je konacno dosadilo svake godine pisati isto. Sad mogu samo dati link.[/size] 8)
[b]Poanta:[/b] "Broj" i "zapis broja" su dva vrlo razlicita pojma.
Broj se moze [color=blue][i]zapisati u nekoj bazi[/i][/color], pri cemu se sam broj ne mijenja, nego samo njegov zapis.
Broj se [u]ne moze[/u] [color=red][i]pretvoriti iz jedne baze u drugu[/i][/color], jer promjena broja znaci da to vise nije isti broj.
Svi kojima ova poanta nije kristalno jasna i/ili ne razumiju zasto je vazna, nastavite citati. Ostali, svejedno procitajte. :P
Ako napisete program koji sadrzi ovako nesto
[code:1]broj_n_u_bazi_b = 0;
potencija_baze = 1;
while (n > 0) {
broj_n_u_bazi_b += potencija_baze * (n % b);
potencija_baze *= 10;
n /= b;
}[/code:1]
vjerojatno cete biti uvjereni da je rijec o "pretvaranju broja u bazu b" ili tako necemu.
No, broj se ne moze "pretvoriti u bazu", nego samo zapisati u njoj. Dakle, da ste ispisivali [tt]n % b[/tt] u gornjoj petlji, zaista biste ispisali znamenke broja [tt]n[/tt] kad ga se zapise u bazi [tt]b[/tt] (redoslijed ispisa je s desna nalijevo, ali to sada nije bitno).
Ono sto vas program radi je da neki broj zamijeni s brojem koji zapisan dekadski izgleda kao ovaj prvi kad se zapise u bazi [tt]b[/tt]. Na primjer, [tex]n = 6[/tex] ce zamijeniti sa [tex]110[/tex]. To mozda izgleda kao da ima smisla jer je [tex](6)_{10} = (110)_2[/tex], ali ne mijenja cinjenicu da je jedan broj [b]sest[/b], a drugi je [b]sto i deset[/b] i oni nemaju veze jedan s drugim!
U nastavku programa cete sa znamenkama broja raditi tako da broj dijelite s 10, no postavlja se pitanje cemu ta gimnastika? Zasto jednostavno ne dijelite stalno s [tt]b[/tt] i zaboravite "pretvaranje"?
Ne bi ovo bilo tako lose, da ne uzrokuje stvarno ozbiljne probleme.
[b]Problem 1:[/b]
Recimo da zelimo nesto raditi s brojem [tex]4096 = 2^{12} = (1000000000000)_2[/tex], sto binarno zapisano ima jednu jedinicu i 12 nula. Pokusate li to "pretvoriti" kako je gore prikazano, dobit cete broj koji, zapisan dekadski, jednako [b]izgleda[/b] kao 4096 zapisan binarno. Dakle, dobit cemo broj koji u dekadskom zapisu ima jednu jedinicu i nakon nje 12 nula.
Problem lezi u neprikazivosti tog broja u standardnoj aritmetici racunala. Naime,
[tex]1000000000000 = (1110100011010100101001010001000000000000)_2[/tex],
sto znaci da za prikaz tog broja treba 40 bitova, a u [tt]int[/tt] stane samo 31 (u [tt]unsigned[/tt] stanu 32 bita) i program se raspadne.
Naravno, mozemo koristiti [tt]long[/tt] ili cak tipove mimo standarda, poput [tt]long long[/tt], ali to samo znaci da cemo uhvatiti sitno brojeva vise. Recimo, broj [tex]1048576 = 2^{20}[/tex] u binarnom zapisu ima jednu jedinicu i 20 nula. Gornjim "pretvaranjem" dobijemo broj koji za zapis trazi 67 bitova. Dakle, nas pocetni broj stane u obicni [tt]int[/tt], a "pretvoreni" ne stane niti u dvostruko vise memorije.
Koristenjem tipa [tt]double[/tt] radimo jos vece zlo, jer se gube znamenke u algoritmu koji bi morao biti cisto cjelobrojni, sto znaci da bi morao imati pouzdano tocan rezultat i ne bi smio pogubiti niti jednu jedinu znamenku.
[b]Problem 2:[/b]
Sto se dogadja u bazama vecim od 10?
Recimo, neka je baza [tt]b = 16[/tt]. "Pretvorimo" li brojeve 11 i 17, dobit cemo identican rezultat: 11. To znaci da negdje dolazi do neke ozbiljne greske, jer ne mogu dva razlicita broja imati jednak zapis. Naravno, stvar je u tome da 11 treba postati B, no takva dekadska znamenka ne postoji, pa "pretvaranje" ispada potpuno pogresno.
[b]Zakljucak[/b]
Nikad, ali stvarno [b][u]NIKAD[/u][/b], nemojte "pretvarati" broj iz jedne baze u drugu. Ako se trazi nesto sa zapisom broja u bazi, dijelite broj s bazom i racunajte znamenke. Ako treba, i nekoliko puta u programu, ali nemojte "pretvarati" samo zato da bi u vecem dijelu programa imali dijeljenje s 10 umjesto s [tt]b[/tt], jer je to jednostavno pogresno.
Ako na nekom kolokviju/ispitu negdje napravite "pretvaranje", ispitivac ima puno pravo samo prekriziti rjesenje kao krivo, bez da uopce gleda sto pise iza tog "pretvaranja".
Ovaj post je nastao jer mi je konacno dosadilo svake godine pisati isto. Sad mogu samo dati link.
Poanta: "Broj" i "zapis broja" su dva vrlo razlicita pojma.
Broj se moze zapisati u nekoj bazi, pri cemu se sam broj ne mijenja, nego samo njegov zapis.
Broj se ne moze pretvoriti iz jedne baze u drugu, jer promjena broja znaci da to vise nije isti broj.
Svi kojima ova poanta nije kristalno jasna i/ili ne razumiju zasto je vazna, nastavite citati. Ostali, svejedno procitajte.
Ako napisete program koji sadrzi ovako nesto
Kod: | broj_n_u_bazi_b = 0;
potencija_baze = 1;
while (n > 0) {
broj_n_u_bazi_b += potencija_baze * (n % b);
potencija_baze *= 10;
n /= b;
} |
vjerojatno cete biti uvjereni da je rijec o "pretvaranju broja u bazu b" ili tako necemu.
No, broj se ne moze "pretvoriti u bazu", nego samo zapisati u njoj. Dakle, da ste ispisivali n % b u gornjoj petlji, zaista biste ispisali znamenke broja n kad ga se zapise u bazi b (redoslijed ispisa je s desna nalijevo, ali to sada nije bitno).
Ono sto vas program radi je da neki broj zamijeni s brojem koji zapisan dekadski izgleda kao ovaj prvi kad se zapise u bazi b. Na primjer, [tex]n = 6[/tex] ce zamijeniti sa [tex]110[/tex]. To mozda izgleda kao da ima smisla jer je [tex](6)_{10} = (110)_2[/tex], ali ne mijenja cinjenicu da je jedan broj sest, a drugi je sto i deset i oni nemaju veze jedan s drugim!
U nastavku programa cete sa znamenkama broja raditi tako da broj dijelite s 10, no postavlja se pitanje cemu ta gimnastika? Zasto jednostavno ne dijelite stalno s b i zaboravite "pretvaranje"?
Ne bi ovo bilo tako lose, da ne uzrokuje stvarno ozbiljne probleme.
Problem 1:
Recimo da zelimo nesto raditi s brojem [tex]4096 = 2^{12} = (1000000000000)_2[/tex], sto binarno zapisano ima jednu jedinicu i 12 nula. Pokusate li to "pretvoriti" kako je gore prikazano, dobit cete broj koji, zapisan dekadski, jednako izgleda kao 4096 zapisan binarno. Dakle, dobit cemo broj koji u dekadskom zapisu ima jednu jedinicu i nakon nje 12 nula.
Problem lezi u neprikazivosti tog broja u standardnoj aritmetici racunala. Naime,
[tex]1000000000000 = (1110100011010100101001010001000000000000)_2[/tex],
sto znaci da za prikaz tog broja treba 40 bitova, a u int stane samo 31 (u unsigned stanu 32 bita) i program se raspadne.
Naravno, mozemo koristiti long ili cak tipove mimo standarda, poput long long, ali to samo znaci da cemo uhvatiti sitno brojeva vise. Recimo, broj [tex]1048576 = 2^{20}[/tex] u binarnom zapisu ima jednu jedinicu i 20 nula. Gornjim "pretvaranjem" dobijemo broj koji za zapis trazi 67 bitova. Dakle, nas pocetni broj stane u obicni int, a "pretvoreni" ne stane niti u dvostruko vise memorije.
Koristenjem tipa double radimo jos vece zlo, jer se gube znamenke u algoritmu koji bi morao biti cisto cjelobrojni, sto znaci da bi morao imati pouzdano tocan rezultat i ne bi smio pogubiti niti jednu jedinu znamenku.
Problem 2:
Sto se dogadja u bazama vecim od 10?
Recimo, neka je baza b = 16. "Pretvorimo" li brojeve 11 i 17, dobit cemo identican rezultat: 11. To znaci da negdje dolazi do neke ozbiljne greske, jer ne mogu dva razlicita broja imati jednak zapis. Naravno, stvar je u tome da 11 treba postati B, no takva dekadska znamenka ne postoji, pa "pretvaranje" ispada potpuno pogresno.
Zakljucak
Nikad, ali stvarno NIKAD, nemojte "pretvarati" broj iz jedne baze u drugu. Ako se trazi nesto sa zapisom broja u bazi, dijelite broj s bazom i racunajte znamenke. Ako treba, i nekoliko puta u programu, ali nemojte "pretvarati" samo zato da bi u vecem dijelu programa imali dijeljenje s 10 umjesto s b, jer je to jednostavno pogresno.
Ako na nekom kolokviju/ispitu negdje napravite "pretvaranje", ispitivac ima puno pravo samo prekriziti rjesenje kao krivo, bez da uopce gleda sto pise iza tog "pretvaranja".
_________________ U pravilu ignoriram pitanja u krivim topicima i kodove koji nisu u [code]...[/code] blokovima.
Takodjer, OBJASNITE sto vas muci! "Sto mi je krivo?", bez opisa u cemu je problem, rijetko ce zadobiti moju paznju.
|