Pas på C og tal

Tags:    c tal bigint

Ville lige dele noget indsigt om C som jeg lige har "genindset".

Jeg sad og kiggede på Project Euler og problem 5 og sad og lavede en løsning
i C, nærmere specific C89. Jeg vidste godt at C havde begrænsede tal, noget man godt kan glemme i de fleste sprog fordi de har typisk en BigInt-agtigt type som bruger de samme operator som andre tal. C89 garanterer kun 4 bytes til en int og det begrænset tallet til for den 'signed' værdi til lidt over 2 milliarder. Men tænkte ikke så meget over det da jeg mente (gættede) at resultat kunne være indenfor dette. Det kunne det sådan set også, men det sidste mellemresultat i min algoritme sendte den op over grænsen.

Hvilke muligheder havde jeg?

1. Først tænkte jeg at på unsigned og større datatype. Men unsigned løser ikke disse problemer for fremtidige tal og en der er ikke garanteret en større datatype i C89. Så skulle jeg skifte til C90 i stedet men problemet ville blot opstå senere.

3. Løsning 3 var at lave algoritmen om og bruge primfaktorer eller lignende i stedet for de store tal, men syntes det ville besværligt og så skulle det gøres i alle fremtidige euler problemer i samme situation.

2. Den anden løsning var at bruge en type der kunne holde større værdier, "uendelige" værdier, en såkaldt BigInt type. Men så skulle alle mine generelle algoritmer laves igen til den nye type fordi +operatoren ikke opererer på typer som ikke er indbygget. Alternativ kunne det løses med noget makrohelvede hvor man definerede om man brugte indbygget eller en BigInt men det lød heller ikke særlig tiltrækkende. Der vidst også noget med at en 'double' kan gemme flere bits (53 ?) og man faktisk godt kan bruge den til heltalsberegninger, men igen samme problem med et begrænset antal bits.

Alle de ting vidste jeg sådan set godt, men der er vidst også et udtryk der lyder at man først lærer noget ordentligt når man er blevet straffet for sine fejl, og det er jeg nu blevet. Jeg har altid syntes at C var et flot sprog og at C++ har jeg ikke kigget så meget på men idéerne så fine ud men syntes at det nu nok kunne gøres i C alligevel. Det kan også gøres i C med det er mere bøvlet. Efter hvad jeg har set om C++ ville det være meget simplere der fordi der understøttes vidst nok generiske typer og algoritmer samt operator overloading. Så jeg kunne både bruge tal og BigInt uden at ændre i algoritmen eller andet endt blot typen faktisk. Så min 'gcd' funktion kunne se sådan her ud i pseudokode:

Fold kodeboks ind/udC++ kode 


Hvor den før var med 'int' i stedet for T. Som sagt det er bare mit gæt men kan nogen med viden om C++ fortælle om det faktisk er sådan at man kan gøre det?

Mit råd er at dem som overvejer at lave noget i C først skal overveje om der er plads til tallene, og hvis der er 1% chance for at et tal ikke kan være i de indbyggede typer så begynd allerede der at overveje hvordan tal og algoritmer skal håndteres. Men at planlægge tingene på forhånd er vel egentaget basisviden som jeg glemte at tage i betragtning.

Nogen der har nogle forslag til hvordan man ellers kan "angribe" tal i C?

Ha' en fortsat god dag :)



Indlæg senest redigeret d. 31.07.2011 14:49 af Bruger #14645
Der findes biblioteker som fx:

GNU MP Bignum Library
MIRACL
IMath

osv osv.

Det er måske ikke alle der understøtter templates og operatoroverstyring

/Christian



Tag et kig her og se hvilke muligheder du har: http://stackoverflow.com/questions/589575/size-of-int-long-etc/589684#589684

Ellers kan man bare hurtigt kaste sin egen BigInt sammen med nogle linked lists.



Tak for svarene.

At bruge en større datatype løser som sagt ikke det grundlæggende problem med begrænsede datatyper. Det kan godt være at en signed long long er stor nok til 99% af alle de tal man kommer over. Den ene procent giver dog så problemet.

Jeg er godt klar over der er biblioteker derude til det / man kan lave sin egen. Hvis jeg skulle lave noget i C som skal bruge store tal ville f.eks. også bruge sådan et bibliotek, for der er ikke andre muligheder - eller det hvertfald det jeg prøver at få afklaret her - om der er andre muligheder.

Det er heller ikke et problem at bruge et sådan bibliotek, men en af pointerne var bare, at man ikke bare kan udskifte den med et andet bibliotek på grund af navne- go API forskelle, uden at ændre alle ens algoritmer - eller komme ud i noget makroværk som i bund og grund er det samme.

Mere "moderne" sprog har muligheder hvor man nemmere kan gøre dette, som templates og operator overloading f.eks..



Indlæg senest redigeret d. 31.07.2011 16:42 af Bruger #14645
Løsningen til opgave 5 overstiger ikke 2 milliarder



Løsningen til opgave 5 overstiger ikke 2 milliarder

Det jeg heller ikke sagt; men et mellemresultat gør:

Her er den første "løsning" jeg valgte:
Fold kodeboks ind/udC kode 

Og outputtet:
Fold kodeboks ind/udKode 

Mellem de 2 sidste går den galt. Min lcm funktion ser sådan her ud:
Fold kodeboks ind/udC kode 

Så det anden sidste tal bliver gange med 20 og går derfor op på omkring 4,6 milliarder og resultat ender med ikke at passe. Men ja der er der mange muligheder til at få netop denne til at compile. Bruge en større datatype, eller ændre lcm:
Fold kodeboks ind/udC kode 

Men alt det gør er at flytte grænsepunktet/problemt til euler nr. 6.

Men denne tråd var ikke ment til at løse et specifikt problem, bare mere til at informere og eventuel give andre muligheder udover dem jeg har nævnt.



Indlæg senest redigeret d. 31.07.2011 17:37 af Bruger #14645
Du kan godt lave en data type (class) i C++ med tilhørende operatorer, der repræsenterer tal af vilkårlig størrelse, og som kan bruges på samme måde (stort set) som de indbyggede data typer.

Jeg vil tro at du kan finde eksisterende kode på nettet, men ellers er det en glimrende øvelse at lave det selv.



t