Avatar billede maqhem Nybegynder
23. juli 2008 - 22:40 Der er 14 kommentarer og
1 løsning

Lommeregner - tal som bits eller tekststrenge

Hej eksperter.

Jeg er gået i gang med overvejelserne om min alt-i-en-lommeregner, som jo af navnets antydning skal kunne alt. Og det er jo ikke så lille et krav faktisk. Jeg vil gerne have, at min lommeregner kan regne med flere milliarder cifre lange tal, og jeg har da overvejet to ting:

* At lave koderne for tallene som binære koder i et gigantisk array.
* At skrive tallet som en tekststreng.

Men kan det ikke passe, at de tegn, der indgår i en tekststreng, alle fylder 16 bit? Hvis jeg har regnet rigtigt, kan jeg i længden ved meget store tal komme med på en 53. del ved brug af de binære koder.
16 * ceil(log_2(n)) / ceil(log(n)) nærmer sig 53,15, når n bliver stor nok.

Og beregninger med et tal skrevet som et kæmpe array med bits kan vel ikke tage længere tid end de normale beregninger, det tager med de normale tal, eftersom computeren vel alligevel omskriver tallene til bits?

Hvis mine informationer er rigtige, og jeg har regnet rigtigt, så kan det godt betale sig. Men hvad så når jeg skal omskrive fra de binære koder til strenge, som kan læses af os menneskelige, så skal der jo regnes en hulens masse. Og når det handler om at lægge et sjovt tal til en lang tekststreng, skal jeg jo så at sige næsten behandle hvert ciffer i tallet. Og det skal jeg jo gøre mange, mange gange. Eksempelvis koden 101001001 skal jo regne 2+16+128+512 ud, og hvert af disse tal skal udregnes ud fra en potens af to. Og når det er gjort, skal strengen også vises, og så husker programmet både på den binære kode og tekststrengen, og så fylder det pludseligt alt for meget. Hvad kan jeg gøre for at lette på det? Jeg vil jo gerne udnytte, at bits fylder ingenting, når nu jeg skal arbejde med gigantiske tal.
Avatar billede arne_v Ekspert
23. juli 2008 - 22:56 #1
char er 16 bit i C# og en string bestaar logisk af et array af char
Avatar billede arne_v Ekspert
23. juli 2008 - 23:01 #2
Du sparer masser af plads ved at gemme binaert fremfor decimalt, men det koster mere
at konvertere for input og output. Det har vaeret kendt i 40-50 aar. Det er den
klassiske diskussion om BCD versus rigtige binaere integers om igen (BCD bruger dog kun
4 bit per ciffer og er derfor noget mere konkurrence dygtig end en char per ciffer !!).
Avatar billede arne_v Ekspert
23. juli 2008 - 23:03 #3
Du skal nok starte med at finde ud af om du er mest interesseret i at kode lommeregner
eller kode store tal.

Er fokus paa lommeregneren saa find en faerdig big integer pakke.

(der er et lille fif - hvis du installerer J# support, saa kan du faktisk faa den fra MS !)

Hvis du selv vil kode den saa har jeg noget kode liggende i stort set alle andre
sprog end C#.
Avatar billede maqhem Nybegynder
23. juli 2008 - 23:26 #4
Mit fokus ligger begge steder, for jeg har en lommeregner allerede, og i en notesblok kan jeg skrive lige så store tal, jeg har lyst til. Men jeg har brug for en lommeregner, der kan regne med kæmpestore tal - og den skal jo selvfølgelig være præcis. Det nytter ikke, at den forsøger at lægge to til 1.8946151081151e+300, fordi det ændrer slet ikke på det store tal alligevel.

Jeg har også overvejet, om man kunne splitte et tal som 12345674891234567489 op i et array af 1234567489 og 1234567489. Så kunne man jo faktisk gemme meget store tal i en Int64[], og det ville ikke tage nogen ressourcer overhovedet at konvertere hele arrayet til en stor streng, der kan regnes på.
Avatar billede maqhem Nybegynder
23. juli 2008 - 23:32 #5
Og visse beregninger som addition og subtraktion kan jo klares meget nemt selv med et tal kløvet i bidder.
Avatar billede arne_v Ekspert
24. juli 2008 - 01:06 #6
Hvis du har J# runtime installeret kan du tilføje en ref til vjslib.dll og
kode som:

using System;

using java.math;

namespace E
{
    public class Program
    {
        public static void Main(string[] args)
        {
            BigInteger v = new BigInteger("1");
            for(int i = 1; i < 100; i++)
            {
                v = v.multiply(BigInteger.valueOf(i));
                Console.WriteLine("fac(" + i + ") = " + v);
            }
            Console.ReadKey();
        }
    }
}
Avatar billede arne_v Ekspert
24. juli 2008 - 01:09 #7
For regning med strenge lavede jeg i 2003 følgende i Pascal til et spørgsmål:

program BigInt;

{$APPTYPE CONSOLE}

uses
  SysUtils;

function numval(c : char) : integer;

begin
  numval := ord(c) - ord('0');
end;

function strval(v : integer) : char;

begin
  strval := chr(ord('0') + v);
end;

function add(v1,v2 : string) : string;

var
  res : string;
  ix1, ix2, tmp, carry : integer;

begin
  res := '';
  carry := 0;
  ix1 := length(v1);
  ix2 := length(v2);
  while (carry > 0) or (ix1 > 0) or (ix2 > 0) do begin
      tmp := carry;
      if(ix1 > 0) then begin
          tmp := tmp + numval(v1[ix1]);
          ix1 := ix1 - 1;
      end;
      if(ix2 > 0) then begin
          tmp := tmp + numval(v2[ix2]);
          ix2 := ix2 - 1;
      end;
      res := strval(tmp mod 10) + res;
      carry := tmp div 10;
  end;
  add := res;
end;

function mulpow10(v : string; pow10 : integer) : string;

var
  res : string;
  i : integer;

begin
  res := v;
  for i := 1 to pow10 do begin
      res := res + '0';
  end;
  mulpow10 := res;
end;

function mulone(v : string; num : integer) : string;

var
  res : string;
  ix, tmp, carry : integer;

begin
  res := '';
  carry := 0;
  ix := length(v);
  while (carry > 0) or (ix > 0) do begin
      tmp := carry;
      if(ix > 0) then begin
          tmp := tmp + num * numval(v[ix]);
          ix := ix - 1;
      end;
      res := strval(tmp mod 10) + res;
      carry := tmp div 10;
  end;
  mulone := res;
end;

function mul(v1,v2 : string) : string;

var
  res : string;
  i : integer;

begin
  res := '0';
  for i := 1 to length(v2) do begin
      res := add(res,mulpow10(mulone(v1,numval(v2[i])),length(v2)-i));
  end;
  mul := res;
end;

var
  i : integer;
  fac : string;

begin
  (* functionality test *)
  writeln(add('1234','12345678'));
  writeln(mulpow10('123',2));
  writeln(mulone('123456',2));
  writeln(mul('12345','12345'));
  (* performance test *)
  fac := '1';
  for i := 1 to 500 do begin
    fac := mul(fac, inttostr(i));
    writeln(i,' ',fac);
  end;
end.
Avatar billede maqhem Nybegynder
24. juli 2008 - 01:11 #8
Hvad kan du ikke kode? Så tror da pokker, du har alle de point. Jeg kigger lige på det, selvom jeg aldrig har skrevet Pascal eller J# før.
Avatar billede arne_v Ekspert
24. juli 2008 - 01:11 #9
Jeg lavede for flere år siden en C++ klasse som lave rigtige binære integers gemt
i bytes med 0.255. Koden kan findes her:

http://www.vajhoej.dk/arne/eksperten/big/int.h
http://www.vajhoej.dk/arne/eksperten/big/int.cpp

(håber at links virker)
Avatar billede arne_v Ekspert
24. juli 2008 - 01:13 #10
Koden er C# ikke J# - jeg misbruger bare J# runtime (som svarer til Java 1.1.4).

Algoritmerne er de samme uanset sprog, så du skal bare kunne læse koden og så forskellig
er sprogene ikke.
Avatar billede arne_v Ekspert
24. juli 2008 - 01:14 #11
Jeg har aldrig haft tid til at lære PL/I !
Avatar billede maqhem Nybegynder
24. juli 2008 - 01:25 #12
Og hvad er PL/I så?
Avatar billede arne_v Ekspert
24. juli 2008 - 01:44 #13
Avatar billede arne_v Ekspert
29. august 2008 - 02:41 #14
all set ?
Avatar billede maqhem Nybegynder
29. august 2008 - 08:12 #15
Tak for svarene.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester