Eli kuinkas kyseinen operaatio oikein tapahtuukaan? Eli jos haluan muuttaa vaikka 2-kantaisen luvun "10010001010" 8-kantaiseksi luvuksi? Tietenkin niin ettei sitä 10-kantaa tarvitsisi sotkea operaatioon laisinkaan :)
https://www.ohjelmointiputka.net/oppaat/opas.
Haku toimii.. :)
EDIT: hups sori, siellä ei ollutkaan oktaalia vaan heksa vaa :< anteex
Ah, ok, kiitos.
Edit:
Eipä vaan eipä tuola ollutkaan sitä tietoa jota hain. Tuola oli vain neuvot kuinka pyöriä kymppikannan ympärillä, mutta ei muuten. Ei se haku taidakaan olla niin kaikkivoipa ;)
Yleisesti tuo taitaa onnistua vain ensin muodostamalla muistiin se luku X, jota merkkijono kuvaa eli käytännössä kertomalla kukin lukualkio sopivalla kantaluvun potenssilla.
Kohdekantaluvun esitys saadaan luvusta käyttäen vuoron perään jakojäännöstä (jolla saa aina viimeisen desimaalin) ja katkaisevaa jakolaskua (jolla siirrytään laskemaan seuraavaa desimaalia).
Kantaluvusta 2 siirtyminen kantalukuun 8 on hiukan erikoistapaus, koska 8 on 2:n potenssi. Niinpä voitkin tehdä kyseisen muunnoksen tarkastelemalla aina 3 bittiä kerralla vähiten merkitsevistä biteistä lähtien. Kun muutat 3 bittisen luvun desimaaliluvuksi saat myös vastaavan 8-kantaisen luvun. Eli
010 010 001 010 2 2 1 2
Olkoon järjestelmän kantaluku a. Esimerkiksi luku 342 voitaisiin tällöin esittää näin:
3 * a^2 + 4 * a^1 + 2 * a^0
Jos tämä sattuisi olemaan 8-järjestelmän luku, se muuntuisi kymmenjärjestelmään laskemalla:
3 * 8^2 + 4 * 8^1 + 2 * 8^0 3 * 64 + 4 * 8 + 2 * 1 226 (kymmenjärjestelmässä)
Tuosta sen saa johonkin muuhun järjestelmään aloittamalla ylhäältä alaspäin. Vaikkapa 2-järjestelmään:
226 / 2^8 = 226 / 256 = 0 (kokonaislukuina; jätetään desimaalit pois) 226 / 2^7 = 226 / 128 = 1 -> 226 - 128 = 98 98 / 2^6 = 98 / 64 = 1 -> 98 - 64 = 34 34 / 2^5 = 34 / 32 = 1 -> 34 - 32 = 2 2 / 2^4 = 2 / 16 = 0 2 / 2^3 = 2 / 8 = 0 2 / 2^2 = 2 / 4 = 0 2 / 2^1 = 2 / 2 = 1 -> 2 - 2 = 0 0 / 2^0 = 0 / 1 = 0
Näin tuli tulokseksi 11100010 binaarijärjestelmässä.
Lukua ei tarvitse muuttaa 10-järjestelmään, jos osaa laskea muissa järjestelmissä.
Esim. luvun 1110002 muunto 7-järjestelmään (710 = 1112).
1110002 / 1112 = 10002 jää 02
10002 / 1112 = 12 jää 12
12 / 1112 = 02 jää 12
Kun jakojäännökset luetaan viimeisestä aloittaen, saadaan vastaukseksi:
1110002 = 1107
Tässä on vain sellainen ongelma, että jakolaskut ovat aika vaikeita, kun ei enää ollakaan tutussa 10-järjestelmässä.
https://www.ohjelmointiputka.net/hak/?kieli=PHP&nimi=base_convert
Jos tuo vaikka toimisi.
Kiitokset Antille. Ja toki muillekin, tästä on hyvät lähtökohdat lähteä kehittämään baseConvert-funktiota (kyllä, varmasti sellaisen joku on jo tehnyt tällekin kielelle). Tarkoitus oli laskeskella noita Rubyllä, joten PHP:n funktio ei tällä kertaa auta.
VB:llä tein nopeasti tällaisen yleispätevän funktion:
Option Explicit Public Function LongToAny(ByVal Value As Long, ByVal System As Byte) As String Const NUMBERS As String = "0123456789ABCDEF" Dim strOut As String If System < 2 Or System > 16 Then Exit Function Do While Value > 0 strOut = Mid$(NUMBERS, Value Mod System + 1, 1) & strOut Value = Value \ System Loop LongToAny = strOut End Function
Muuttaa annetun luvun merkkijonoksi mihin tahansa lukujärjestelmään binääristä heksaan. Toiminta-aluetta voi lisätä pidentämällä NUMBERS-vakiota lisämerkein. Koodin pitäisi olla tarpeeksi yksinkertainen, jotta sen voi portata nopeasti muillekin kielille :)
Optimoitavaa tuossa sitten on vaikka kuinka, esim. on varmaankin hyvin mahdollista laskea etukäteen kuinka pitkä muuttujasta tulee ja varata tarpeeksi muistia kertaalleen, ettei tarvitse kokoajan muistia varailla uudelleen, kuten tuossa ylläolevassa koodissa. Itselläni ei kuitenkaan ole minkäänlaista tarvetta tälle, joten en tätä tästä eteenpäin kehittele.
Hyödytöntä kikkailua tullut värkättyä, mutta laitanpa tänne jos jotakuta kiinnostaa (tai ehkä joku vieläpä hyötyy joskus hakua käytettäessä). Tuo yleismuunnin on vielä vaiheessa, mutta katselin huvikseni Wikipediasta muuta lukujärjestelmiin liittyvää. Törmäsin kaavaan jolla saa laskettua aikas tehokkaasti 8- ja 16-kantaiset luvut 10-kantaiseksi luvuksi:
(((d1 * base + d2) * base + d3) * base + d4)...
Luvussa 1571 d1 on siis 1, d2 on 5, d3 on 7 ja d4 on 1.
Kokeilin tuota piruuttani, ja vertasin sitä tuohon yleisempään laskemiskeinoon, eli tähän:
d1 * base^n + d2 * base^(n-1) + d3 * base^(n-2)...
Missä siis n on d on sama kuin edellisessä, ja n on lukua vastaavan merkkijonon pituus.
Nopeusetu oli merkittävä tuolla ensimmäisellä tavalla, suoritusaika Rubyllä oli vain noin lähes puolet siitä mitä tuolla toisella tavalla laskettuna.
Foobatin mainitsema tapa (erikoistapaus 8 ja 16 kantaisilla luvuilla ja binääriluvuilla käpisteltäessä) näyttäisi myös äärimmäisen tehokkaalta, saa nähdä jaksanko sitäkin kokeilla. Voisi tästä jo siirtyä vähän hyödyllisempiinkin juttuihin välissä ;)
Itse asiassa tuo nopeampi laskutapa toimii kaikista lukujärjestelmistä 10-järjestelmään.
Esim. luku 34567 muutetaan 10-järjestelmään:
3*73 + 4*72 + 5*71 + 6*70 = 3*343 + 4*49 + 5*7 + 6 = 1266
((3 * 7 + 4) * 7 + 5) * 7 + 6 = (25 * 7 + 5) * 7 + 6 = 180 * 7 + 6 = 1260 + 6 = 1266
Kaava on helposti johdettavissa tarkastelemalla yhteen laskettavien numeroiden yhteisiä tekijöitä.
Niinpäs näyttääkin, käsitin kaiketi en.Wikipedian selotuksen jotenkin väärin. Enkä hoksinut tuota johtamistakaan... Toisaalta tuota toista (hitaampaa) tapaa näkee käytettävän vähän kaikkialla (esimerkiksi OP:n oppaissa ja ohjeissa ;), joten en hoksinut edes ajatella asiaa.
Tuohan on siis Hornerin menetelmä polynomin laskentaan! Sellainenkin tarina on, että joku yli kymmenen vuotta sitten hyvinkin suositun VAX-prosessoriarkkitehtuurin assemblerissa on ollut ihan oma käskynsä "laske tämän asteen polynomin arvo näillä kertoimilla ja tällä äksän arvolla käyttäen Hornerin menetelmää".
Sehän on täsmälleen sama kaava hieman erilaisessa muodossa. Aivan kuten x2+x
on sama kuin x(x+1)
Niin, sama polynomihan se siinä on vain esitettynä eri tavoilla, siksi lopputuloskin on sama. Laskentamenetelmien tehokkuudessa vain saattaa olla suuriakin eroja. Taikka sitten tarkkuudessa, sillä esimerkiksi liukulukujen tapauksessa useiden lukujen summa kannattaisi laskea niin päin, että ensin lasketaan pienillä luvuilla ja isot ynnätään vasta viimeiseksi.
Tosin, tässä lukujärjestelmätapauksessa tuo homma toimii kai näin vain kun jostakin n-kantaisesta lukujärjestelmästä ollaan muuttamassa lukua koneen sisäiseen esitystapaan, joka on yleensä 2-järjestelmä. Ja silloinhan tuo menee ihan luonnostaan tällä Hornerin menetelmällä, sillä jos vaikka 7-järjestelmän luku on numerosarja 152643, aloitetaan lopputuloksen kerryttäminen vasemman laidan ykkösestä ja siitähän sitä sitten edetään kertomalla seiskalla ja lisäämällä lukuja niin kauan kuin niitä piisaa. Mutta lopputulos on siis koneen sisäisessä esitysmuodossa, eli jos ulos pitääkin saada luku vaikka 9-järjestelmässä, onkos siihen paljon muuta konstia kuin ruveta sitten ottamaan lopputuloksesta ysin jakojäännöstä ja osamäärää kunnes jaettavaa ei enää ole ja tulostaa lasketut jakojäännökset käänteisessä järjestyksessä?
Aihe on jo aika vanha, joten et voi enää vastata siihen.