Terve!
olisi sellainen ongelma c-kielellä ohjelmoitaessa,että pitäisi saada ohjelma laskemaan lukuja joiden pituus on jopa 1000 numeroa(luvut luetaan tiedostosta),eli kysymyksessä on todella suuret luvut.
miten tämä onnistuisi? - kokeilin itse jo laskea long doublen avulla mutta en saanu sitä toimimaan,vaikka long doublenhan vissiin pitäisi näyttää lukuja suurinpiirtein 10^4000 asti.jos se onnistuu long doublen avulla niin miten luku ensin määritellään ja miten se tulostetaan?kokeilen jo tälleen menestymättä:
long double arvo1=0.0; long double arvo2=0.0; long double tulos =0.0; scanf("%Lf", &arvo1) scanf("%Lf", &arvo2); tulos = arvo1+arvo2; printf("%Lf", tulos);
tämä tulostaa tulokseksi nolla, ja scanf lukee lukuja vain ensimmäiset 17 kunnolla,loput on nollia(tai 17 numeron jälkeen luvut 0 tai vääriä).
eli kysymys kuuluu, että onko minulla jotain määrittelyissä vikana,vai onko sitten jokin muu keino laskea tiedossa olevia lukuja(yhteen,jakaa,kertoa tai vähentää).
(ohjelmana on dev-c++ ja codeBlocks uusimmat versiot- molemmilla sama ongelma)
kiitos kaikille,jotka jaksoitte lukea romaanini! :)
(Mod. Edit. Ja kiitos kaikille, jotka käytätte jatkossa kooditageja. ;))
Haulla löytyi seuraavat keskustelut, joista luulisi olevan hyötyä:
Eka ja toka.
Molemmissa päädyttiin apukirjastojen käyttöön, että siitä.
Voithan myös lukea luvun manuaalisesti. Tässä tapauksessa täytyy tietenkin ottaa huomioon, että vaikka long double ehkä pystyykin käsittelemään noin isoja lukuja, ei sen tarkkuus ole kuin muutama kymmenen desimaalia (merkitsevää numeroa).
Jos laskettavat luvut ovat kokonaislukuja (eivätkä siis liukulukuja kuten viimeksi oletin), laskut voi suorittaa merkkijonojen avulla.
Tuo tulostuksen virheellisyys taitaa johtua tuosta printf-funktiosta eikä niinkään luvuista. Itselläniki on ollut ongelmia tulostaa long double tyyppisiä muuttujia. Tuo "%Lf" ei vaan tunnu toimivan oikein, vaan se näyttää käyttävän muuttujaan siten kuin siinä olisi vähemmän bittejä kuin siinä oikeasti on. Ehkä ongelma johtuu käännösympäritöstäni (Window XP, vanha gcc), ehkä jostain muusta. Jos long double tyyppiä tarvitaan vain laskennan tarkkuuden takia eikä niinkään arvoalueen, voidaan se castata double tyyppiseksi ennen tulostusta ja tulostaa "%lf"-määreellä, joka tuntuisi toimivan.
sqwiik kirjoitti:
Jos laskettavat luvut ovat kokonaislukuja (eivätkä siis liukulukuja kuten viimeksi oletin), laskut voi suorittaa merkkijonojen avulla.
mitenhän tuo merkkijonojen avulla laskeminen oikein tapahtuu..?kehtaisko joku hieman jeesata.eli kysymys on kokonaisluvuista. :)
EDIT: Taisikin olla c eikä c++. No eiköhän tätä voi soveltaa jotenkin.
Heitelläänpä hatusta jonkin näköistä purkkaa. En tiedä toimivuudesta ja tehokkuudesta.
Niin ja tarvitset funktiot int2char() ja char2int().
string luku1 = "98934859835478237894792837489789675498"; string luku2 = "12738476854900000000000000000000435665"; string tulos; // Pari apuria int iapu = 0; int iapu2 = 0; char capu = 'c'; // Selvitetään, kumpi luvuista lyhyempi for (int i = 0 ; i < lyhyempi.length() ; ++i) { // Lasketaan lukujen vastinnumerot yhteen iapu = iapu2 + char2int( lyhyempi.at( lyhyempi.length()-i ) ) + char2int( pitempi.at( pitempi.length()-i ) ); iapu2 = 0; // Menikö yli kympin? if ( iapu >= 10 ) { // Ykköset kirjaimiksi capu = int2char( iapu % 10 ); // Ylimääräinen kymppi talteen seuraavaa kierrosta varten iapu2 = 1; } else { capu = int2char( iapu ); } // Lisätään saatu numero tulokseen tulos = capu + tulos; } // Jos iapu2:een jäi ykkönen, tässä vaiheessa pitää se lisätä tulokseen // oikean merkin kohdalle mutta en jaksa. // Muuten laitetaan tuloksen alkuun pidemmästä luvusta alkupätkä tulos = pidempi.substr(0, pidempi.length()-lyhyempi.length() ) + tulos;
olen vielä tosi noviisi ohjelmoinnissa niin eipä hirveästi aukene toi TsaTsaTsaan esimerkki,koska se on C++:lla..mutta jos joku kehtais tehdä tuon funktion tai ohjelman pätkän c:llä niin olisin todella kiitollinen, ja oppisi itsekkin vähän lisää noista silmukoista ja merkkijonoista.
kiitos jo etukäteen..!
Ja mitähän toi manuaalinen luvun lukeminen tarkoittaa?
bug85 kirjoitti:
Ja mitähän toi manuaalinen luvun lukeminen tarkoittaa?
Jos kysymys koski minun viestiäni, niin siinä tapauksessa se tarkoittaa sitä, että et lue lukuja suoraan scanf-funktiolla, jos se ei kerran siihen pysty. Sen sijaan luet luvut sisään merkkijonoina ja muunnat itse ne merkkojonoista luvuiksi. Tulostamisen kanssa lienee sama homma.
Mutta kuten sanoin, sisäänrakennetut liukulukutyypit pystyvät varastoimaan luvun vain muutaman kymmenen merkitsevimmän numeron tarkkuudella, ei tässä välttämättä ole paljoakaan järkeä. Siispä vaikkapa luvut:
100000000000000000000000000000000000000000000000
100000000000000000000000000000000000000000000000
(luultavasti myös vaikkapa 100000000000000000000000000000000000000000000000
muuttuvat mitä suurimmalla todennäköisyydellä samaksi luvuksi long doubleksi muutettaessa. Näin ollen kummatkin (ne kaikki) voisi syöttää sisään parinkymmenen desimaalin tarkkuudella (tässä tapauksessa riittää yksi desimaali) kymmenpotenssimuodossa: 1E77.
bug85 kirjoitti:
Ja mitähän toi manuaalinen luvun lukeminen tarkoittaa?
Vaikka sitä, että sinulla on taulukoissa/merkkijonoissa laskettavien lukujen numerot/merkit ja sitten toteutat yhteenlaskut tai kertoalgoritmin itse käyttäen näitä numeroita/merkkejä. Esim. yhteenlaskussa lasket lukujen numerot erikseen yhteen ja jos arvo on yli kymmenen, lisäät seuraavaan numeroon yhden ja vähennät nykyisestä 10. Tästä ideasta voi tietenkin kehittää hiukan tehokkaampia ratkaisuja, jotka laskevat useampia numeroita kerralla.
C:llä kirjoitettuna käytetään sitten char-taulukkoa. Sitten vain ynnäämään lukuja ala-asteella opitulla tavalla ^_-.
Tässä koodia, mutta funktiomuotoa en jaksa vääntää, ja tässä lasketaan vain luvut yhteen. Kerto- ja jakolaskutkin voi rakentaa samalla periaatteella (kerto- ja jakopuu).
/* Nämä on sitten varattu jollain tavalla & luettu tiedostosta */ char * luku1 = "192136412821374192342374235763240957236523"; char * luku2 = "673529478374963274628356834857324562389"; char tulos[1000]; int len1 = strlen(luku1), len2 = strlen(luku2), pituus, lyhyt, muisti = 0, a, vali; /* Pidempi & lyhyempi */ pituus = (len2>len1)?len2:len1; lyhyt = (len2<len1)?len2:len1; tulos[pituus] = '\0'; /* Lopetusmerkki valmiiksi */ for(a = 0; a < pituus; a++){ /* Numeroita otetaan lyhyemmästä luvusta */ if(a < lyhyt){ /* - '0' jotta saadaan oikea numeerinen arvo + <muisti> */ vali = (luku1[len1 - a] - '0') + (luku2[len2 - a] - '0') + muisti; /* Lyhyempi luku loppunut; nyt lisätään enää 0:ia lyhyemmän numeroiden sijasta. */ }else{ /* luku1 on pitempi */ if(len1 == pituus)vali = (luku1[len1 - a] - '0') + muisti; else vali = (luku2[len2 - a] - '0') + muisti; } /* Jos menee yli 10, niin siirto muistiin seuraavaa kierrosta varten; muuten 0. */ if(vali > 10){ vali -= 10; muisti = 1; }else muisti = 0; tulos[pituus - a] = vali + '0'; }
Koodin toimivuudesta ei takeita.
Kertoisitko muuten, onko kyse kokonaisluvuista vai reaaliluvuista(liukuluvuista)? Entä täytyykö lukujen säilyä täysin tarkkoina, ja jos ei, niin kuinka tarkkoina? Tässä ketjussa asiaa on käsitelty vähän siltä sun tältä kantilta.
bug85 kirjoitti:
...Eli kysymys on kokonaisluvuista. :)
.
Ja mielestäni tuloksen täytyy säilyä tarkkana.
sqwiik kirjoitti:
bug85 kirjoitti:
...Eli kysymys on kokonaisluvuista. :)
.
Ja mielestäni tuloksen täytyy säilyä tarkkana.
No hups, pitäisi lukea tarkemmin näitä ketjuja. Siinä tapauksessa minun hölinäni noista liukuluvuista saa unohtaa (lukuunottamatta sitä kuuluisaa manuaalista lukemista).
Jos tuloksen tosiaan täyttyy olla "tarkka" (kuten yleensä kokonaislukujen ollessa kyseessä on tapana), lienevät ainoat mahdollisuudet tosiaan käyttää valmiita kirjastoja tai koodata itse omat laskutoimitus- ja io-rutiinit.
GMP on ihan käyttökelpoinen kirjasto varmasti C:llekin, vaikka en olekaan itse siitä käyttänyt kuin C++-wrappereita. Jos ei ole tarkoitus keksiä pyörää uudelleen, ei turhaan kannata. (Tietenkin toisinaan on mukava keksiä pyöriä sun muita uudestaan.) Dev-C++:n kanssa kannattaa tietenkin vilkaista, josko tuolle löytyisi Dev-Pak, niin onnistuisi asentaminen vaivatta.
Kiitoksia oikein paljon kaikille.Tosi hienoa,että toisia autetaan ku ollaan hädässä.. :)
EDIT:En ite ainakaan saa toimimaan tuota sqwiikin ohjelmaa kun se tulostaa tulokseksi mitä sattuun.mutta pitänee vielä yrittää.
eli nyt sain toimimaan tuo sqwiikin esimerkin.nyt pitäis vielä värkätä samanlaiset mutta vähennys-,jako- ja kertolaskuja laskevat.
Aihe on jo aika vanha, joten et voi enää vastata siihen.