Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C++: 128-bittinen kokonaisluku

Sivun loppuun

peki [06.12.2004 00:49:21]

#

Osaisiko kukaan kertoa, kuinka voisin tehdä 128-bittisen etumerkittömän kokonaislukumuuttujan, joka kykenee suorittamaan peruslaskutoimituksia?
Kuinka voisin tähän muuttujaan muuten lukea std:n cinillä arvon?
Onko tavoite todella haastava vai onko se vain muutaman kymmenen koodirivin päässä?

Metabolix [06.12.2004 01:18:58]

#

Ei se kohtuuttoman haastava ole... Riippuu siitä, mitä odotat noilta luvuiltasi. Perustoimitukset menevät vielä ihan helposti. Heitänpä nyt tähän pikaisen esimerkin:

class TLuku
{
public:
  unsigned long A, B, C, D; /* D = Merkitsevin, A = vähiten merkitsevä */
  void Lisaa(TLuku *X);
  void Vahenna(TLuku *X);

  void Aseta(unsigned long _D, unsigned long _C, unsigned long _B, unsigned long _A)
    {A = _A; B = _B; C = _C; D = _D;};

  TLuku() {A=B=C=D=0;};
  ~Luku(){};
};

TLuku::Lisaa(TLuku *X)
{
  unsigned long Apu1, Apu2;

  Apu1 = A;
  A += X->A;
  Apu2 = B;
  B += X->B + (A < Apu1 ? 1 : 0); /* Jos Apu < A, on tapahtunut "kymmenylitys" */
  Apu1 = C;
  C += X->C + (B < Apu2 ? 1 : 0);
  Apu2 = D;
  D += X->D + (C < Apu1 ? 1 : 0);

  if (D < Apu2) cout << "Ei mahtunut!\n";
}

TLuku::Vahenna(TLuku *X)
{
  unsigned long Apu1, Apu2, Apu3, Apu4;

  Apu4 = D;
  D -= X->D;

  Apu3 = C;
  C -= X->C;
  if (Apu3 < C) D--; /* Lainaus merkitsevämmistä numeroista */

  Apu2 = B;
  B -= X->B;
  if (Apu2 < B) C--;
  if (Apu3 < C) D--;

  Apu1 = A;
  A -= X->A;
  if (Apu1 < A) B--;
  if (Apu2 < B) C--;
  if (Apu3 < C) D--;

  if (Apu4 < D) cout << "Negatiivinen!\n";
  /* Tämän voisi tarkistaa joka välissä */
}

Tuolta pohjalta voisit osata tehdä kerto- ja jakolaskutkin. Lukeminen cin-oliosta toimii niin, että luet tavalla tai toisella luvut "unsigned long" -olioihin ja siirrät niistä. Ei mikään helppo juttu välttämättä, koska pitää huomioida heksa- ja kymmenjärjestelmien ero:
4294967295 mahtuu yhteen unsigned long-muuttujaan.
4294967296 ei mahdu.
Kirjoitan tuon tapaisen muuttujan jossakin vaiheessa ihan kunnolla, mutta nyt en oikein jaksa, onhan kello sentään 1:20.

On se niin vaikeaa kirjoittaa koodia suoraan tuohon viestinkirjoitusruutuun... Sitä voisi suurentaa vähän. Toivottavasti ei tullut virheitä.

Oletan nyt koko ajan, että unsigned long on 32-bittinen, kuten se toistaiseksi tavallisella kotikoneella on. Kenenkään on siis turha tulla halkomaan hiuksia sen koosta, vaikka se jollakin arkkitehtuurilla olisikin 64-bittinen tai jotakin muuta.

peki [06.12.2004 01:22:07]

#

Kiitos. Tuosta osaankin jo soveltaa.

Jaska [07.12.2004 20:41:51]

#

Gnu Multiple Precision Arithmetic library on avoimen lähdekoodin projekti, jossa on valmiina nopeat isojen kokonaislukujen käsittelyyn tarvittavat funktiot. http://www.swox.com/gmp/

peki [07.12.2004 20:52:23]

#

Tuo onkin erittäin hyödyllinen kirjasto!
Vaikutti erittäin laadukkaalta.

Koipio-ohjelma [08.12.2004 17:57:36]

#

Tämä nyt on kyllä ihan turha viesti, mutta ihmettä sinä 128-bittisellä luvulla teet? Siihenhän mahtuu ainakin luvut 0-miljardi(en tiedä kuinka paljon siihen mahtuu, mutta se kuvastaa sen suuruutta. Siis olettaen että siinä ei ole etumerkkiä.

Ja eikös muuttujat yleensä määritellä privateiksi? Näin ainakin minä teen ja eikös se ole hyvän ohjelmointi tavan mukaista? Tai näin ainakin minä olen ymmärtänyt. Eli koodi menisi:

class TLuku
{
private:
  unsigned long A, B, C, D; /* D = Merkitsevin, A = vähiten merkitsevä */
public:
  void Lisaa(TLuku *X);
  void Vahenna(TLuku *X);

  void Aseta(unsigned long _D, unsigned long _C, unsigned long _B, unsigned long _A)
    {A = _A; B = _B; C = _C; D = _D;};

  TLuku() {A=B=C=D=0;};
  ~Luku(){};
};

//ohjelma koodi...

TLuku::Lisaa(TLuku *X)
{
  unsigned long Apu1, Apu2;

  Apu1 = A;
  A += X->A;
  Apu2 = B;
  B += X->B + (A < Apu1 ? 1 : 0); /* Jos Apu < A, on tapahtunut "kymmenylitys" */
  Apu1 = C;
  C += X->C + (B < Apu2 ? 1 : 0);
  Apu2 = D;
  D += X->D + (C < Apu1 ? 1 : 0);

  if (D < Apu2) cout << "Ei mahtunut!\n";
}

TLuku::Vahenna(TLuku *X)
{
  unsigned long Apu1, Apu2, Apu3, Apu4;

  Apu4 = D;
  D -= X->D;

  Apu3 = C;
  C -= X->C;
  if (Apu3 < C) D--; /* Lainaus merkitsevämmistä numeroista */

  Apu2 = B;
  B -= X->B;
  if (Apu2 < B) C--;
  if (Apu3 < C) D--;

  Apu1 = A;
  A -= X->A;
  if (Apu1 < A) B--;
  if (Apu2 < B) C--;
  if (Apu3 < C) D--;

  if (Apu4 < D) cout << "Negatiivinen!\n";
  /* Tämän voisi tarkistaa joka välissä */
}

Blaze [08.12.2004 18:07:51]

#

Koipio-ohjelma kirjoitti:

Siihenhän mahtuu ainakin luvut 0-miljardi(en tiedä kuinka paljon siihen mahtuu, mutta se kuvastaa sen suuruutta. Siis olettaen että siinä ei ole etumerkkiä.

Kaks potenssiin 128, eli luku, joka alkaa 34 ja jatkuu 37:llä muulla numerolla :)

Edit: siis noin 34 miljoonaa kvintiljoonaa :)
(Lähde: http://koti.mbnet.fi/henrihe/tiede/suuretluvut.html)

Koipio-ohjelma [08.12.2004 18:33:59]

#

Joo noin on. Laskeminen on sinänsä mukavaa, mutta ei noin isojen lukujen, joten en viittinyt laskea sitä. Ja se arvaus meni hieman alakanttiin, mutta se tekee vielä yhden kysymyksen: Mitä tuollaisella luvulla tekee? En minä ainakaan keksi mitään sovellusta joka tuollaisia lukuja tarttee, paitsi ehkä joku älyttömän monimutkainen fysiikka moottori tai jokin...

Metabolix [08.12.2004 18:50:45]

#

Kopioi-ohjelma kirjoitti:

Ja eikös muuttujat yleensä määritellä privateiksi? Näin ainakin minä teen ja eikös se ole hyvän ohjelmointi tavan mukaista? Tai näin ainakin minä olen ymmärtänyt. Eli koodi menisi: ...

Yleensähän ne tosiaan on tapana määritellä privateksi (minulla ei, koska ei siitä julkisuudesta haittaakaan ole), mutta jos ne tuossa määriteltäisiin privateiksi, niitä ei voitaisi noissa Lisaa- ja Vahenna-funktioissa lukea toisesta luvusta (TLuku *X), ja uskoisin, että koodi toimii noin nopeammin kuin jos kukin jäsen haettaisiin jäsenfunktiolla:
unsigned int GetA() {return A;};
jne.

Jaska [08.12.2004 19:11:57]

#

Kryptografiassa tarvitaan suuria kokonaislukuja. Ainakin RSA:ssa. Samoin kuin lukuteoriassa.

tn [08.12.2004 21:54:35]

#

Metabolix kirjoitti:

Yleensähän ne tosiaan on tapana määritellä privateksi (minulla ei, koska ei siitä julkisuudesta haittaakaan ole), mutta jos ne tuossa määriteltäisiin privateiksi, niitä ei voitaisi noissa Lisaa- ja Vahenna-funktioissa lukea toisesta luvusta (TLuku *X), ja uskoisin, että koodi toimii noin nopeammin kuin jos kukin jäsen haettaisiin jäsenfunktiolla.

Niinhän minäkin ennen luulin, kunnes karu totuus selvisi. Todellisuudessa privaattius on luokkakohtaista eikä oliokohtaista, ja luokan metodit/funktiot pääsevät käsiksi parametrina välitetyn saman luokan olion tietoihin aivan kuin ne olisivat julkisia. Näin asia on C++:n lisäksi myös ainakin Javassa.

peki [08.12.2004 22:15:52]

#

Kyseistä lukua aion soveltaa juuri salauksessa, lukuteoriassa, sekä ennen kaikkea eräässä ensimmäisistä c-ohjelmistani. Kyseinen yksinkertainen ohjelma tutkii, onko luku alkuluku. Haluaisin nyt kuitenkin pitkän ajan jälkeen laajentaa ohjelmaa tukemaan myös huomattavasti suurempia lukuja.


Sivun alkuun

Vastaus

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

Tietoa sivustosta