Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C++: Binääristä kymmenlukumuotoon

Sivun loppuun

Mieliala [25.08.2005 15:56:49]

#

Täällä on mainostettu, että kysymys ei juuri koskaan ole tyhmä, jos vain se on ymmärrettävä. Koettelen teitä:

Tavukoodista sain jo järjellisen näköistä ja nyt sitten binaarimuotoista tietoa pitäisi saada kymmenlukumuotoon siten, että se jaettaisiin kymmenlukuina tyhjään taulukkoon merkkien lukumäärän mukaan. No, tuo ei ollut kauhean selvästi ilmaistu, joten kerron toisin: Minulla on dataa muodossa 01101010101010101101000101010101 (kohtuullinen määrä, tekstitiedostona 195KB), ja tarvitsen sen paitsi kymmenlukumuotoon, myös jaettuna niin, että tekstin "Huh" jälkeen tulisi kaksi merkkiä, sanan "Hah" jälkeen taas kaksi merkkiä, sanan "Hei" vaikkapa kolme merkkiä (sanomakuvauksen mukaan) jne. Binäärimuodosta kymmenlukumuotoon varmaan vielä onnistuu (sekin vasta pienen rappaamisen ja kirosanojen jälkeen [koska en ole perehtynyt aiheeseen ikuna]), mutta tulostaminen tuohon "taulukkoon" kyllä lamauttaa luovuuteni tyystin - kun ei osaa, niin ei osaa!

...Minun ei pitänyt _tehdä_ tällaista ohjelmaa, vaan tutkia tällaisen ohjelman antamia tuloksia ohjearvoihin, mutta koska tällaista "kääntöohjelmaa" ei sitten meillä ollutkaan, tässä ollaan...

Niin, olette kilttejä, jos neuvotte taas minua alkuun. En toki kaipaa valmista ohjelmaa, vaan vinkkejä, kuinka tämän voi toteuttaa. Olen todella aloittelija tässä ohjelmoinnissa, tai oikeammin: tätä ei ole ikinä tarvinnut tehdä, joten jos tahdotte auttaa, teette sen parhaiten selittämällä oikein tarkkaan. ;)

Mazuli [25.08.2005 18:18:00]

#

siis haluatko muuttaa binääri luvun kymmenluku muotoon? vai mitä?

Metabolix [25.08.2005 23:10:41]

#

Tuo jakaminen kirjainten perään jäi aika epäselväksi, joten jos viitsit tarkentaa vähäsen... Ja mitä kieltä pitäisi käyttää?

Mieliala [26.08.2005 08:02:40]

#

Kyllä. Paljon binääriä kymmenlukumuotoon.

Eikö ole hienoa ohjelmasuunnittelua, kun en tiedä, mitä kieltä tässä kannattaisi käyttää? C:ta olen nyt katsellut, ja muita kieliä olenkin tutkinut vielä paljon vähemmän.

Tuo datan jakaminen. Data siis tulee erään mittarin antureilta, ja näitä on noin 1000 kpl. Se tulee tietyssä järjestyksessä, ja tietyiltä reseptoreilta tulee tiettyjä tietoja (edelleen epäselvääkö?). Sanomakuvauksessa on selvitetty tämä tietojen järjestys, sekä se, monellako merkillä sitä kuvataan.
--- Eli sanomakuvauksessa on merkitty, että tienpinnan lämpötilaa esitetään kahdella merkillä, ilman lämpötilaa kahdella merkillä, veden lämpötilaa kahdella merkillä ja auton sisälämpötilaa myös kahdella. Jos minulla on käännetyssä datanauhassa pätkä 56282034, niin se tulisi esittää näin:
tienpinnan lämpötila 56
ilman lämpötila 28
veden lämpötila 20
auton sisätilan lämpötila 34.

Lieko tuokaan selventänyt yhtään. No, ei muuta kuin kokeilemaan...

Metabolix [26.08.2005 09:14:53]

#

Kyllä se selvensi, paljonkin. Kokeile saada tästä jotakin irti. Autan kyllä mielelläni lisää, kun pääsen taas koneelle, mutta en ehdi nyt selitellä tätä pätä paremmin.

#include <stdio.h>
#include <stdlib.h>

/* Asettaa bin_pituuteen bin-muuttujan merkkien määrän (- 0-merkki)
** ja dec_pituuteen tiedon, montako merkkiä luku tulee viemään */
void luvun_pituus(char * bin, int * dec_pituus, int * bin_pituus)
{
    int i, j;

    /* Jos bin_pituutta ei annettu */
    if (!bin_pituus)
        bin_pituus = &i;

    // Mitataan muuttujan pituus; char-taulun tulee loppua nollatavuun.
    for (*bin_pituus = 0; bin[*bin_pituus]; (*bin_pituus)++) {}

    // Vähennetään edessä olevat nollat
    for (j = 0; bin[j] == '0'; j++) {}

    // Lasketaan 10-järjestelmässä tarvittava numeromäärä
    if (dec_pituus)
        *dec_pituus = (int)(log10(2.0) * ((*bin_pituus) - j)) + 1;
}

/* Siirtää annetun bin-luvun dec-luvuksi.
** Muista ensin varata tarvittava char-taulu,
** hyödynnä edellistä funktiota */
void bin_to_dec(char * bin, char * dec)
{
    int i, j, len;
    int bin_pituus, dec_pituus;

    /* Lasketaan pituudet */
    luvun_pituus(bin, &dec_pituus, &bin_pituus);

    /* Laitetaan 1. numero valmiiksi */
    dec[dec_pituus - 1] = (bin[0] == '1' ? 1 : 0);

    /* Silmukka: kerrotaan tulos kahdella ja
    ** lisätään siihen käsiteltävän bitin arvo */
    i = 1;
    len = dec_pituus - 1;
    while (bin[i] == '0' || bin[i] == '1')
    {
        /* Kerrotaan joka numero kahdella */
        for (j = len; j < dec_pituus; j++)
        {
            dec[j] <<= 1;
            /* Kymmenylitys */
            if (dec[j] > 9)
            {
                dec[j] -= 10;
                dec[j-1]++;
                if (j-1 < len)
                    len = j-1;
            }
        }

        /* Lisätään tämä bitti */
        if (bin[i] == '1')
            dec[dec_pituus - 1]++;

        /* Next... */
        i++;
    }

    /* Muunnetaan oikeiksi merkeiksi: */
    /* Tyhjät pois alusta */
    for (i = 0; !dec[i]; i++) {}

    /* 0 => '0', 1 => '1' */
    for (j = 0; i < dec_pituus; j++, i++)
    {
        dec[j] = dec[i] + '0';
    }
    dec[j] = 0;
}

int main(void)
{
    char *bin;
    char *dec;
    int bin_pituus, dec_pituus;
    int i;

    char buf[64];

    /* Pyydetään binääriluvun pituus ja varataan sille muistia */
    printf("Anna binääriluvun pituus:\n  ");
    scanf("%i", &bin_pituus);
    bin = (char *) calloc(bin_pituus + 1, 1);

    /* Luodaan "format string", jolla luetaan käyttäjältä binääriluku */
    sprintf(buf, "%%%is", bin_pituus);

    /* Luetaan binääriluku */
    printf("Anna binääriluku (max. %i merkkiä):\n  ", bin_pituus);
    scanf(buf, bin);

    /* Lasketaan sen pituus 10-järjestelmän lukuna */
    luvun_pituus(bin, &dec_pituus, &bin_pituus);
    printf("%i => %i\n", bin_pituus, dec_pituus);

    /* varataan muistia 10-järjestelmän luvulle */
    dec = (char *) calloc(dec_pituus + 1, 1);

    /* Muunnetaan */
    bin_to_dec(bin, dec);

    /* Tulostetaan */
    printf("%s = %s\n", bin, dec);

    /* vapautetaan muisti */
    free(bin);
    free(dec);
    return 0;
}

Mazuli [26.08.2005 18:53:21]

#

tämä muuttaa ehkä vähän lyhyemmin

int BinToDec(char *bin)
{
  int len = strlen(bin);
  int sum = 0;
  for(int i = 0; i < len; i++){
    if(bin[i] == '1'){
      sum += pow(2,i);
    }
  }
  return sum;
}

Metabolix [26.08.2005 21:20:19]

#

Mazuli: Funktiossasi on virhe: se lukee binäärilukua väärään suuntaan, eli "1000" tulkitaan luvuksi 1. Tulitko muuten edes ajatelleeksi, että tuo minun funktioni muuttaa sen suoraan kymmenlukumuotoiseksi tekstiksi, jolloin sillä saa aikaan suurempiakin lukuja kuin 4294957295 (2^32-1)? Ajattelin nyt koko sitä 192kt:ta. Sitä paitsi ei missään tapauksessa kannata käyttää pow-funktiota, se on hidasta. Jos tuota tapaa haetaan, niin näin:

int bin_to_dec(char * bin)
{
  int result = 0, val = 1, i;

  for (i = 0; bin[i]; i++);
  for (i--; i >= 0; i--)
  {
    if (bin[i] == '1')
      result += val;
    val <<= 1;
  }
  return result;
}

Vieläkin jäi hieman epäselväksi, kuinka tuo bittijono on muodostettu, eli mistä tietää, montako seuraavaa bittiä muodostavat seuraavan luvun?

Grey [28.08.2005 17:33:38]

#

Hm, tavukin koostuu biteistä, eli miksei voisi loputtomien 1 ja 0 merkkien sijaan tallentaa ihan oikeana binaaryna. Pienentyisi tiedostonkoko aivan kivasti ja muistiakin menisi siinä sivussa vähemmän..

-Grey-

Mieliala [29.08.2005 13:46:41]

#

Hmm, liitin Metabolixin koodiin vain math.c:n niin alkoi toimia, sitä ennen herjasi logaritmista. No mutta onpa hienoa!
Nyt yritän vielä ymmärtää tarkalleen, mitä tuossa koodissa oikeastaan lukee. Olisi kiva oppia ohjelmoimaan.

//hihi, jätän nyt teille tuon math.c:n ilahduttamaan arkipäivää. Näin asiantuntevasti puhuu aloitteleva koodari. ;)

Metabolix [29.08.2005 16:21:37]

#

Yleensä on tapana liittä .h- eikä .c-tiedostoja :)

Tuon koodin ymmärtämistä helpottaa tieto, että "x <<= 1" on sama kuin x:n kertominen kahdella, kun kyseessä on kokonaisluku. Siitä eteenpäin se pitää vain ymmärtää, tai sitten ottaa kynä ja paperia (tai kirjoitusohjelma) ja suorittaa koodia omin käsin rivi riviltä :)


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta