Forum: Mikrocontroller und Digitale Elektronik Fakultaet berechnen auf dem STK500mit AtMega16


von Paul P. (cpn)


Lesenswert?

Hallo Leute,
Ich möchte gerne ein Programm schreiben, bei dem die Fakultäten der 
Zahlen 1-200 berechnet werden (Auf die letzte Stelle genau). Diese 
sollen in Arrays berechnet werden und die Ein/Ausgabe geschieht über 
Hyperterminal, also über die RS323 Verbindung.

Programme für Fakultäten gibt es viele im Netz, nur leider alle für PC's 
und Assembler.
Ich lege zwei Arras für zwischenberechnung mit einer größe von jeweils 
400 an. (In jede Stelle vom Array kommt eine Zahl hinein. Das Array hat 
400 Stellen, da die Fakulltät von 200 insgesamt 375Stellen hat.)

Mich würde interessieren, wie ich die Zwei Schleifen zur berechnung 
schreiben soll/kann...

Desweiteren, wie ich den Carry(Übertrag) realisiere.

Vielen Dank für eure Antworten.

lg Paul

von Karl H. (kbuchegg)


Lesenswert?

Paul P. schrieb:

> Ich lege zwei Arras für zwischenberechnung mit einer größe von jeweils
> 400 an. (In jede Stelle vom Array kommt eine Zahl hinein. Das Array hat
> 400 Stellen, da die Fakulltät von 200 insgesamt 375Stellen hat.)
>
> Mich würde interessieren, wie ich die Zwei Schleifen zur berechnung
> schreiben soll/kann...

Genauso wie du es sonst auch machen würdest. Der einzige Unterschied 
besteht darin, dass du nicht die eingebauten Operatoren * und + benutzen 
kannst, sondern auf deine eigenen Funktion zurückgreifen musst, die die 
Multiplikation von grossen Zahlen erledigt (dort wirst du auch den + 
Operator benötigen)

> Desweiteren, wie ich den Carry(Übertrag) realisiere.

In einer Addition, wo der Carry einer einzigen Stelle maximal 0 ooder 1 
sein kann:

    Digit = DigitA + DigitB + Carry;
    if( Digit > 10 ) {
      Carry = 1;
      Digit -= 10;
    }
    else
      Carry = 0;

Du machst genau dasselbe, was du auch mit Papier und Bleistift machst, 
wenn du mit großen Zahlen rechnest (also mit dem auswendig gelernten 
kleinen EinmalEins nicht mehr weiterkommst).

Vielleicht solltest du erst mal beobachten, was genau du am Papier 
machst, wenn du 2 Zahlen addierst und das in einem Program (am PC) 
nachbilden.


Ich denke übrigens nicht, dass du das am Mega16 hinkriegen wirst. 
Überschlagsmässig benötigst du nämlich 3 400-stellige 'Variablen'. In 
der Multiplikation wird noch ein zusätzliches 'Register' benötigt. Aber 
das werden dir deine Vorübungen am PC schon zeigen :-)

von Gast (Gast)


Lesenswert?

>Überschlagsmässig benötigst du nämlich 3 400-stellige 'Variablen'.

Für was denn das? Er braucht a) Speicherplatz für eine einzige 
375-stellige BCD-Zahl und b) das Know-How, wie man diese Zahl mit einer 
Zahl multipliziert, die zwischen 1 und 200 liegen darf. Dann muss er 
sich nur noch die zur Fakultätsdefinition n° = 1  2  3 * ... * n 
passende Schleife konstruieren. Ich schätze die Berechnung von 200! auf 
einem ATMega16 als völlig unproblematisch ein. Er sollte das Ergebnis 
innerhalb eines Sekundenbruchteils errechnen können.

von Lasse S. (cowz) Benutzerseite


Lesenswert?

Selbst Matlab auf meinem Rechner sagt nur noch:

factorial(200) = inf


ich würde daher von einer Umsetzung auf dem AVR absehen (wofür 
eigentlich?) und entweder auf eine Näherung oder eine Tabelle 
ausweichen.

Gruß
Lasse

von Karl H. (kbuchegg)


Lesenswert?

Gast schrieb:
>>Überschlagsmässig benötigst du nämlich 3 400-stellige 'Variablen'.
>
> Für was denn das? Er braucht a) Speicherplatz für eine einzige
> 375-stellige BCD-Zahl und b) das Know-How, wie man diese Zahl mit einer
> Zahl multipliziert, die zwischen 1 und 200 liegen darf.

Du hast recht.
Der Multiplikator wird ja gar nicht so gross.

Hab ich übersehen.

von Martin (Gast)


Lesenswert?

ich würde einfach eine LUT für die 200 Werte machen...

Martin

von Tim S. (maxxie)


Lesenswert?

Wofür eigentlich?

Ich kann mir gerade keine sinnvolle Aufgabenstellung vorstellen, bei der 
man entsprechend große Fakultäten braucht.

von Martin (Gast)


Lesenswert?

>> Selbst Matlab ...

Seit wann ist denn Matlab ein Maßstab?

http://www.wolframalpha.com/input/?i=200!

von yalu (Gast)


Lesenswert?

Martin schrieb:
> ich würde einfach eine LUT für die 200 Werte machen...

Je nach verwendetem Zahlenformat könnte das etwas knapp werden: Nimmt
man BCD, braucht man etwas mehr als 16KiB, der ATmega16 ist dafür zu
klein. Nimmt man die Binärdarstellung, reichen schon etwas weniger als
14KiB, dafür braucht man zusätzlichen Code für die benutzerfreundliche
Ausgabe (falls das überhaupt erwünscht ist).

> Seit wann ist denn Matlab ein Maßstab?
>
> http://www.wolframalpha.com/input/?i=200%21

Das Problem hat sich damit auf die Implementierung eines einfachen
HTTP-Clients reduziert ;-)

von Gast (Gast)


Lesenswert?

>wofür eigentlich?

Vielleicht einfach, um etwas dabei zu lernen? Um Erkenntnisse zu 
gewinnen? Um ein Gefühl dafür zu bekommen, welche Aufgaben mit einem µC 
von der Leistungsklasse leicht, schwer oder garnicht zu lösen ist? Um 
sich am Erlebnis zu freuen, ein Problem erfolgreich gelöst zu haben? Man 
kann es als Denksportaufgabe und geistige Herausforderung betrachten. Es 
ist sicher ein besserer Zeitvertreib als nur zu fragen "wofür 
eigentlich?".

von Udo R. S. (Gast)


Lesenswert?

Wenn Du die Zahlen BCD kodierst kannst Du 2 Ziffern in ein Byte packen. 
Nur die Multiplikation und Additionsfunktion wird dann etwas 
unübersichtlicher.

Oder Du machst einen Übertag bei 100, dann hast Du auch 2 Ziffern in 
einem Byte, kannst die Ziffern aber nicht mehr so schön eine nach dem 
anderen ausgeben.

Die Funktionen zum Addieren und Multiplizieren selbst mach mal schön 
selber sonst ist der Lerneffekt = null :-))

Gruß, Udo

von Mark B. (markbrandis)


Lesenswert?

Es klingt eher so, als ob man hier einen Algorithmus braucht, mit dem 
man eine bestimmte Ziffer des Ergebnisses berechnen kann. Für pi gibt es 
so einen, wenn ich micht nicht irre, vielleicht ja auch für die 
Fakultät? Hat nur irgendwie eher wenig mit Mikrocontrollerprogrammierung 
zu tun, sondern mehr mit Mathematik... man könnte das Problem (mit dem 
obigen Ansatz) ja auch erst mal auf einem PC oder Mac grundsätzlich 
lösen, und sich dann an die Portierung machen. Wobei ich mir jetzt 
sinnvollere Aufgaben vorstellen kann, als im Debugger 375 Stellen eines 
Arrays durchzugehen. Zum Beispiel eine schöne Fouriertransformation mit 
Ausgabe auf einem LCD... da lernt man auch viel wenn man sie selbst 
ausprogrammiert, genug Mathe ist allemal drin, und es gibt sogar 
sinnvolle Anwendungen dafür. ;-)

von Udo R. S. (Gast)


Lesenswert?

Klingt für mich eher nach einer Aufgabe für einen Azubi oder 
Anfangssemester der keine Lust auf selber programmieren hat.

von Gast (Gast)


Lesenswert?

>Klingt für mich eher nach...

An so etwas Schlimmes wollen wir mal lieber nicht denken ;-)

von Hagen R. (hagen)


Lesenswert?

>Für pi gibt es
>so einen, wenn ich micht nicht irre, vielleicht ja auch für die
>Fakultät?

Ja gibt es, sogar sehr effizient.

von Paul P. (cpn)


Lesenswert?

-> Ich bin nicht zu faul zum selber programmieren, mir fehlt nur ein 
Ansatz.
-> Desweiteren kenne ich auch die Stirling Formel zur Näherung. Aber bis 
ich die geschrieben habe, hab ich die Additio/multiplikation selber 
schneller gemacht.
Ich habe halt sowas noch nie geschrieben, aber jetzt hab ich ein paar 
Anhaltspunkte und versuche mal übers Wochenende eine Addierfunktion zu 
schreiben, die so addiert, wie man selber von Hand.

In den Arrays werden die Zahlen binär abgespeichert. Ich muss dann nur 
noch den Nulloperator zum beenden von Strings auf 0xFF ändern. Kp wie^^

Also danke für eure Antworten, ich meld mich :)

lg Paul

von Mark B. (markbrandis)


Lesenswert?

Hagen Re schrieb:
> Ja gibt es, sogar sehr effizient.

Link bitte?

von Gast (Gast)


Lesenswert?

Vergiss die Stirlingformel.

Der Dreh- und Angelpunkt ist die Frage, wie man 625371837 x 946 
(allgemeiner: eine sehr große Zahl mit einer dreistelligen Zahl) 
berechnen kann, wenn man nur (1) das kleine Einmaleins kennt und (2) 
addieren kann.

Das geht so:

6 x 9 =  54
6 x 4 =   24
6 x 6 =    36
2 x 9 =   18
2 x 4 =    08
2 x 6 =     12
5 x 9 =    45
5 x 4 =     20
5 x 6 =      30
3 x 9 =     27
3 x 4 =      12
3 x 6 =       18
7 x 9 =      63
7 x 4 =       28
7 x 6 =        42
1 x 9 =       09
1 x 4 =        04
1 x 6 =         06
8 x 9 =        72
8 x 4 =         32
8 x 6 =          48
3 x 9 =         27
3 x 4 =          12
3 x 6 =           18
7 x 9 =          63
7 x 4 =           28
7 x 6 =            42
         ------------
         591601757802

Überrascht? :-) Warum das aber so funktioniert und warum man die vielen 
zweistelligen Zahlen genau so und nicht anders einrücken muss und wie 
man daraus eine Routine für nen µC basteln kann, und dass der 
Rechenaufwand für eine Multiplikation nach diesem Schema lächerlich 
gering ist (nämlich nur proportional zur Stellenanzahl der großen Zahl) 
und dass Du so z. B. auch problemlos das Produkt 945! x 946 berechnen 
könntest, wenn nur die Dezimalziffern von 945! in einem Array 
gespeichert vorliegen - das alles herauszufinden überlasse ich Dir :-) 
Viel Spaß!

von Tim S. (maxxie)


Lesenswert?

Gast schrieb:
>>wofür eigentlich?
>
> Vielleicht einfach, um etwas dabei zu lernen? Um Erkenntnisse zu
> gewinnen? Um ein Gefühl dafür zu bekommen, welche Aufgaben mit einem µC
> von der Leistungsklasse leicht, schwer oder garnicht zu lösen ist? Um
> sich am Erlebnis zu freuen, ein Problem erfolgreich gelöst zu haben? Man
> kann es als Denksportaufgabe und geistige Herausforderung betrachten. Es
> ist sicher ein besserer Zeitvertreib als nur zu fragen "wofür
> eigentlich?".

Versteh mich nicht falsch, ich mag es selber Dinge auszuprobieren.

Allerdings halte ich die Fakultät für sehr langweilig dazu. Hier gibt es 
kaum etwas "Neues" für jemanden, der (schriftlich) Addieren und 
Multiplizieren kann.

Zudem ist der Anwendungsbereich des "Spielzeuges" am Ende sehr mau. Man 
will dann doch auch mal sein entwickeltes Programm in einem 
entsprechenden Kontext laufen sehen.

Wenn du an soetwas aber echt Interesse hast, empfehle ich dir den 
nächsten Schritt: Die Ackermann-Funktion :-)

von Gast (Gast)


Lesenswert?

>Ackermann-Funktion

(lach) Ich lehne dankend ab ;-) (Mir ist das ganze Zeug bekannt...)

Das mit dem Interesse kann man nicht so verallgemeinern, denke ich. Das 
ist doch individuell höchst unterschiedlich. Der eine findet ein 
Knight-Rider-Lauflicht oder die Propellerclock interessant, der andere 
ein Programm, dass eintausend pi-Nachkommastellen ausrechnet (was 
übrigens auch auf einem ATmega16 möglich wäre), oder selbst eine 
Quicksort-Routine zu schreiben, obwohl das auch schon tausendmal gemacht 
wurde. Auch das Schreiben von Programmen ohne am Ende vorzeigbar 
blinkendes oder dröhnendes Ergebnis kann Spaß machen. Finde ich :-)

Leute, die nicht schriftlich multiplizieren und addieren können, scheint 
es übrigens durchaus zu geben. Jeder, der behauptet hat, dass ein 
ATmega16 mit der Aufgabe überfordert ist, gehört dazu.

von Hagen R. (hagen)


Angehängte Dateien:

Lesenswert?

@mark:

http://www.delphipraxis.net/topic65632.html&postdays=0&postorder=asc&start=20

erklärt dir erstmal wie man die Fakultät mit der geringsten Komplexität 
berechnen kann. Dh. dieser Rechenweg basierend auf A.Schönhage ist der 
schnellste um die Fakultät zu großen Zahlen zu berechnen. Mit ihm kann 
man aber auch viel mehr sehr schnell berechnen, zb. eben die Anzahl der 
endenen Dezimalstellen zu einer belieben Zahlenbasis der Fakultät. 
Benutzt man modulare Arithmetik zb. zur Basis 10000 so kann man mit 
einfachen Integern die letzten Ziffern der Fakultät berechnen. Alle 
anderen kombinatorischen Funktionen wie Permutation/Kombination kann man 
damit sehr effizient berechen.

Im Attachment mal meine Versuche mit solchen Berechnungen, allerdings 
auf PCs mit ordentlich Leistung da man ja rechnen möchte und nicht 
unbedingt die Herausforderung sucht sowas mit 4 Bit Mini-Low-Power-MCUs 
zu berechnen ;) Ist schon eine ziemlich verrückte Idee.

Gruß Hagen

von Tim S. (maxxie)


Lesenswert?

"sehr Effizient"
Naja ich weiss ja nicht. Ich tendiere dazu von Effizienz zu reden, wenn 
es in polynomieller Zeit zur Eingabegröße berechenbar ist.

Da aber bereits die Ziffernzahl der Ausgabe zur Ziffernzahl der 
Eingabegröße exponential steigt dürfte das hier nicht der Fall sein.

von avr (Gast)


Lesenswert?

Das Problem ist wohl nur der Speicher. Mit 2 Feldern
(altes/neues Ergebnis) in Binär ist es wohl leicht.

Spassig wäre in "packed BCD" (ein Byte enthält 2 Ziffern)
um die serielle Übertragung zu vereinfachen (Übertragung
als ASCII durch BCD-Nibble +48).
Richtig gut ist, wenn nur ein Feld benötigt wird.

So ist es wirklich reizvoll wenn auch unnütz.
Aber Sudoku ist auch unnütz und trotzdem beliebt ;)

avr

von Hagen R. (hagen)


Lesenswert?

>"sehr Effizient"
>Naja ich weiss ja nicht. Ich tendiere dazu von Effizienz zu reden, wenn
>es in polynomieller Zeit zur Eingabegröße berechenbar ist.
>Da aber bereits die Ziffernzahl der Ausgabe zur Ziffernzahl der
>Eingabegröße exponential steigt dürfte das hier nicht der Fall sein.

Laber laber, es gibt zZ. kein besseres Verfahren und mehr kannst du bei 
Arnold Schönhage und Peter Borwein nachlesen.

Davon abgesehen frage ich mich wie du von "exponentielles Wachstum der 
Eingabeziffernzahl zu Ausgabeziffernzahl" zu dem Schluß kommst das die 
verwendete Formel eine spezifische Komplexität hätte. Das eine hat mit 
dem anderen garnichts zu tun.

Die Komplexität dieser Formel, basierend auf der Primfaktorzerlegung, 
ist O(n*(log(n)*log(log(n))^2) und besser gehts heutzutage nicht, rechne 
dir mal das aus !

Gruß Hagen

von Tim S. (maxxie)


Lesenswert?

Ich behaupte auch nicht, dass es besser geht. Ich behaupte, dass es 
nicht effizient geht.

Ich würde gern mal sehen, wie du mit p(n) Aufwand eine Ausgabe von x^n 
für alle n > N. n,N in setN Länge erzeugen kannst...

von Hagen R. (hagen)


Lesenswert?

>Ich behaupte auch nicht, dass es besser geht. Ich behaupte, dass es
>nicht effizient geht.

ich verstehe dich schon richtig. Mein Problem ist das du "effzient" 
absolut betrachtest und nicht in Relation zu den Alternativen.

>"sehr Effizient"
>Naja ich weiss ja nicht. Ich tendiere dazu von Effizienz zu reden, wenn
>es in polynomieller Zeit zur Eingabegröße berechenbar ist

Du leitest also Effizienz absolut von der Eingangsgröße ab. Ich leite 
Effizienz von der Eingangsgröße in Relation zu den zur Alternative 
stehenden Verfahren ab. Warum halte ich das für sinnvoller ? Ganz 
einfach nach deiner Meinung kann man 1+1 sehr effizient berechnen und N! 
kann man nicht effizient berechen. Das problem dabei: Was hat die 
Berechnung von 1+1 mit N! zu tun ?

Gruß Hagen

von doofi (Gast)


Lesenswert?

Fakultät ist langweilig.
Die Harten rechnen das Ackermannsche Funktional auf dem 8-Bitter...

von Ben _. (burning_silicon)


Lesenswert?

wozu das eigentlich? die dinger sind konstanten und alle die ein atmega 
in seinem leben berechnen könnte sind bekannt. mit den größeren zahlen 
hat ja ein 3ghz core2 schon seine probleme wenn man es mit mul/add 
durchrechnet.

nur um rauszukriegen ob der µC das kann? klar kann der das, solange es 
in sein RAM passt - was die zahlen wohl eher im unteren bereich halten 
dürfte. oder du bastelst noch ein interface für ein externes RAM, aber 
dann ist der atmega nicht mehr viel schneller als ein besserer 
taschenrechner.

in meinen augen ist das entweder eine nette programmier-idee wenn man 
zuviel zeit hat oder stromverschwendung.

von Peter D. (peda)


Lesenswert?

Für ne Zahl mit 375 Dezimaltellen braucht man 156 Byte.
Das ganze Programm paßt also dicke in nen ATtiny45 rein.


Peter

von Ben _. (burning_silicon)


Lesenswert?

klar passen die kleinen zahlen. interessant wirds ja erst bei den 
richtig großen.

von Karl H. (kbuchegg)


Lesenswert?

Ben _ schrieb:
> klar passen die kleinen zahlen. interessant wirds ja erst bei den
> richtig großen.

Na ja.
Soooo interessant ist das auch wieder nicht.
Nichts gegen BCD Arithmetik. Aber in der Praxis braucht man die eher 
selten.
Wenn schon, dann ist das höchstens eine Übung im Umgang mit Arrays, 
wobei da der Wert allerdings zweifelhaft ist.
Lerneffekt ist IMHO maximal, dass ein gewisses Verständnis entsteht wie 
Zahlensysteme eigentlich funktionieren und was wir tun, wenn wir mit 
Papier und Bleistift rechnen.

Das geht aber auf dem PC genausogut. Da muss ich mir nicht die Tortur 
antun, das alles auf einem µC zu implementieren, bei dem ich keinen 
Unterbau habe, der mir die Routineaufgaben wie zb. Ausgabe, abnimmt.

von Volker Z. (vza)


Lesenswert?

Anbei meine Fingerübung. Es ist zwar speziell auf die Aufgabe angepasst, 
aber nicht optimiert.
Also wer kan es besser (performanter & efizienter).

Der Programmierwetbewerb ist eröffnet!


@OT Versuch mal das Programm zuverstehen. Dabei kan man auch eine Menge 
lernen.

von Volker Z. (vza)


Lesenswert?

1
#include <stdio.h>
2
#include <string.h>
3
4
5
#define LAENGE 400
6
7
void to_bcd(int fak,unsigned char *bcd)
8
{
9
   while(fak)
10
   {
11
      *bcd++ = fak%10;
12
      fak /= 10;
13
   }
14
}
15
16
void print_bcd(unsigned char *bcd)
17
{
18
   unsigned char *pBcd = bcd +(LAENGE-1);
19
20
   while(pBcd>=bcd && *pBcd ==0)
21
      pBcd--;
22
23
   while(pBcd>=bcd)
24
   {
25
      putchar('0' + *pBcd--);
26
   }
27
   putchar('\n');
28
}
29
30
31
void bcd_mul(unsigned char *multiplikator,unsigned char *multiplikand ,unsigned char *produkt)
32
{
33
   unsigned char temp;
34
   unsigned char *pro,*mul;
35
   int i,j;
36
37
   memset(produkt,0,LAENGE);
38
   for(i=0;i<3;i++)
39
   {
40
      mul = multiplikand;
41
      for(j=0;j<(LAENGE-1)-i;j++)
42
      {
43
         pro = produkt+i+j;
44
         temp = *multiplikator * *mul;
45
//printf("%i * %i = %i  (%i)\n",*multiplikator,*mul,temp,i+j);
46
         do 
47
         {
48
            temp  += *pro;
49
            *pro++ = temp%10;
50
            temp /= 10;
51
         } while(temp);
52
53
         mul++;
54
      }
55
      multiplikator++;
56
   }
57
}
58
59
unsigned char mul[LAENGE];
60
unsigned char tmp[LAENGE];
61
unsigned char fakulaet[LAENGE];
62
63
int main(int argc, char* argv[])
64
{
65
   int fak;
66
   while(1)
67
   {
68
     printf("Fakultaet (1-200 0=Abruch)\n");
69
      scanf("%i",&fak);
70
      if(fak<1) break;
71
      if(fak<=200)
72
      {
73
         memset(tmp,0,sizeof(tmp));
74
         to_bcd(fak,tmp);
75
//print_bcd(tmp);
76
         while(--fak)
77
         {
78
//printf("---%i\n",fak);
79
            memset(mul,0,sizeof(mul));
80
            to_bcd(fak,mul);
81
//print_bcd(mul);
82
            bcd_mul(mul,tmp,fakulaet);
83
//            print_bcd(fakulaet);
84
            memcpy(tmp,fakulaet,LAENGE);
85
         }
86
         fputs(" = ", stdout );
87
         print_bcd(fakulaet);
88
      }
89
   }
90
  return 0;
91
}

von Martin (Gast)


Lesenswert?

Wie ist denn die Laufzeit deines Programms, Volker?

von Volker Z. (vza)


Lesenswert?

Habe ich noch nicht gemessen. Läuft bislang auch nur auf dem PC.

von Volker Z. (vza)


Lesenswert?

So hier die Laufzeiten:

Profile: Function timing, sorted by time
Date:    Fri Nov 27 14:55:20 2009


Program Statistics
------------------
    Command line at 2009 Nov 27 14:55: 
"C:\projects\fakultaet\Debug\fakultaet"
    Total time: 6161,032 millisecond
    Time outside of functions: 1,326 millisecond
    Call depth: 2
    Total functions: 4
    Total hits: 401
    Function coverage: 100,0%
    Overhead Calculated 4
    Overhead Average 4

Module Statistics for fakultaet.exe
-----------------------------------
    Time in module: 6159,706 millisecond
    Percent of time in module: 100,0%
    Functions in module: 4
    Hits in module: 401
    Module function coverage: 100,0%

        Func          Func+Child           Hit
        Time   %         Time      %      Count  Function
---------------------------------------------------------
    6122,115  99,4     6159,706 100,0        1 _main (fakultaet.obj)
      31,967   0,5       31,967   0,5      199 _bcd_mul (fakultaet.obj)
       5,535   0,1        5,535   0,1        1 _print_bcd 
(fakultaet.obj)
       0,091   0,0        0,091   0,0      200 _to_bcd (fakultaet.obj)

von Karl H. (kbuchegg)


Lesenswert?

Nict sehr aussagekräftig, weil da offenbar die scanf Zeit auch mit dabei 
ist.

Mach doch eine Schleife von 1 bis 200 und lass die jeweilige Fakultät 
ausrechnen. Mittels clock misst die die Laufzeit für jede einzelne Zahl. 
Das ist viel interessanter, wie die Zeit wächst, wenn die Zahlen größer 
werden.
Bei derartigen Laufzeitmessungen ist der Trend interessant, nach dem die 
Zeit größer wird, wenn die Argumente anwachsen.

von Tim S. (maxxie)


Lesenswert?

Kleine Verbesserungsvorschläge:

Die BCD-Mul, die du benötigst muss nicht über die vollständige 
reservierte Zahlenlänge laufen. In der n-ten Multiplikation ist die 
Anzahl der zu betrachtenden Stellen nach oben durch n * 
log_10(multiplikant) < n * 3 beschränkt.
Spart dir für die ersten 130 Multiplikationen viel Aufwand.

Durch den Übertrag in der do-while deiner Multiplikation kann es in 
deiner Implementierung zu Pufferüberläufen kommen (wenn das unsigned 
char ausgereizt wird) ist zwar ausserhalb der Anforderungen, sollte dann 
aber nur zu einem fehlerhaften Ergebnis aber zu keiner Korruption des 
Speichers führen.

von Volker Z. (vza)


Lesenswert?

Hier mal die Laufzeiten der Verschiedenen Fakultäten:

Pentium4  2,4GHz (Debug)


freq is 3579545 p
3 0.239 ms
4 0.357 ms
5 0.475 ms
6 0.593 ms
7 0.712 ms
8 0.831 ms
9 0.949 ms
10 1.068 ms
11 1.188 ms
12 1.345 ms
13 1.426 ms
14 1.546 ms
15 1.665 ms
16 1.834 ms
17 1.905 ms
18 2.026 ms
19 2.147 ms
20 2.265 ms
21 2.475 ms
22 2.509 ms
23 2.710 ms
24 2.753 ms
25 2.871 ms
26 2.995 ms
27 3.140 ms
28 3.314 ms
29 3.365 ms
30 3.486 ms
31 3.610 ms
32 3.757 ms
33 3.864 ms
34 3.987 ms
35 4.109 ms
36 4.310 ms
37 4.365 ms
38 4.491 ms
39 4.639 ms
40 4.755 ms
41 4.872 ms
42 5.001 ms
43 5.191 ms
44 5.254 ms
45 5.382 ms
46 5.537 ms
47 5.646 ms
48 5.929 ms
49 5.933 ms
50 6.026 ms
51 6.242 ms
52 6.292 ms
53 6.447 ms
54 6.575 ms
55 6.684 ms
56 6.850 ms
57 6.958 ms
58 7.127 ms
59 7.246 ms
60 7.529 ms
61 7.515 ms
62 7.648 ms
63 7.788 ms
64 7.982 ms
65 8.052 ms
66 8.246 ms
67 8.347 ms
68 8.759 ms
69 8.633 ms
70 8.754 ms
71 9.014 ms
72 9.012 ms
73 9.199 ms
74 9.300 ms
75 9.519 ms
76 10.397 ms
77 9.706 ms
78 10.167 ms
79 10.122 ms
80 10.159 ms
81 10.501 ms
82 10.450 ms
83 10.605 ms
84 11.325 ms
85 10.885 ms
86 11.027 ms
87 11.523 ms
88 13.114 ms
89 11.584 ms
90 11.726 ms
91 11.759 ms
92 11.914 ms
93 12.105 ms
94 12.234 ms
95 12.386 ms
96 13.344 ms
97 13.485 ms
98 13.127 ms
99 13.039 ms
100 13.203 ms
101 13.263 ms
102 13.443 ms
103 13.650 ms
104 13.851 ms
105 13.958 ms
106 14.074 ms
107 14.218 ms
108 14.555 ms
109 14.571 ms
110 14.670 ms
111 14.910 ms
112 15.047 ms
113 15.503 ms
114 15.375 ms
115 15.487 ms
116 15.809 ms
117 15.870 ms
118 16.202 ms
119 16.925 ms
120 16.327 ms
121 16.471 ms
122 16.651 ms
123 16.920 ms
124 17.073 ms
125 17.146 ms
126 17.271 ms
127 18.015 ms
128 17.641 ms
129 17.777 ms
130 17.923 ms
131 18.188 ms
132 22.747 ms
133 18.441 ms
134 18.618 ms
135 18.778 ms
136 19.145 ms
137 19.179 ms
138 19.314 ms
139 20.207 ms
140 20.051 ms
141 19.850 ms
142 20.065 ms
143 20.303 ms
144 21.228 ms
145 20.541 ms
146 20.687 ms
147 21.081 ms
148 21.157 ms
149 21.298 ms
150 21.484 ms
151 21.947 ms
152 21.904 ms
153 22.780 ms
154 22.519 ms
155 22.308 ms
156 22.682 ms
157 22.836 ms
158 23.184 ms
159 23.629 ms
160 23.294 ms
161 23.727 ms
162 25.501 ms
163 23.843 ms
164 24.257 ms
165 24.237 ms
166 24.521 ms
167 25.736 ms
168 24.807 ms
169 25.044 ms
170 25.196 ms
171 25.668 ms
172 25.634 ms
173 25.819 ms
174 26.365 ms
175 27.310 ms
176 26.425 ms
177 26.590 ms
178 27.104 ms
179 27.102 ms
180 27.156 ms
181 27.297 ms
182 27.960 ms
183 27.947 ms
184 28.318 ms
185 28.636 ms
186 28.403 ms
187 30.433 ms
188 28.999 ms
189 30.303 ms
190 31.001 ms
191 30.979 ms
192 29.936 ms
193 30.180 ms
194 30.712 ms
195 31.733 ms
196 30.873 ms
197 31.020 ms
198 31.182 ms
199 32.057 ms
200 31.715 ms

von yalu (Gast)


Lesenswert?

Jetzt, wo die Sau raus ist: Ich habe gestern auch mal so ein Programm
zusammengestrickt, habe es aber nicht gleich veröffentlicht, da ich
dachte, Paul möchte sich sicher erst selber ein paar Gedanken dazu
machen ;-)

Das Programm berechnet (ohne Benutzerinteraktion) nacheinander alle
Fakultäten bis 200 und gibt sie auf dem Bildshirm aus. Dazu braucht es
1
   33ms  mit Ausgabe ins XTerm-Fenster
2
  700µs  mit Ausgabe nach /dev/null
3
  175µs  ohne Ausgabe (mit auskommentiertem print_bignum-Aufruf)

Zur Messung der Zeiten habe ich den Inhalt von main 100- bzw. 100000-
mal ausführen lassen. Der Rechner hat einen Core2 Duo T7500 mit 2,2GHz.

Das Programm bräuchte auf einem ATtiny85 508B Flash und etwa 400B RAM.
Ich hab's aber noch nicht damit getestet.
1
#include <stdio.h>
2
#include <stdint.h>
3
#define MAXDIGITS 375
4
5
typedef struct {
6
  uint16_t ndigits;
7
  uint8_t digits[MAXDIGITS];
8
} bignum_t;
9
10
void mul(bignum_t *pn1, uint8_t n2) {
11
  uint16_t nd = pn1->ndigits, i, prod;
12
  uint8_t *pd = pn1->digits, carry=0;
13
14
  for(i=0; i<nd || carry && i<MAXDIGITS; i++) {
15
    prod = (i<nd ? *pd * n2 : 0) + carry;
16
    carry = prod / 10;
17
    *pd++ = prod - 10 * carry;
18
  }
19
  pn1->ndigits = i;
20
}
21
22
void print_bignum(bignum_t *pn) {
23
  uint16_t i = pn->ndigits;
24
  uint8_t *pd = pn->digits+i;
25
26
  while(i--)
27
    putchar(*--pd + '0');
28
  putchar('\n');
29
}
30
31
int main(void) {
32
  bignum_t x = {1, {1}};
33
  uint8_t i;
34
35
  for(i=1; i<=200 ; i++) {
36
    mul(&x, i);
37
    print_bignum(&x);
38
  }
39
  return 0;
40
}

von Gast (Gast)


Lesenswert?

Schau an, schon am nächsten Tag gibt es zwei fertige Proggis im Thread. 
Und just jene, die eben noch erklärt haben, wie uninteressant und 
langweilig diese Sache doch ist, sind die ersten, die 
Verbesserungsvorschläge zu den Programmen präsentieren. Leute, Leute... 
;-)

von Tim S. (maxxie)


Lesenswert?

Erm ... es ist uninteressant.

Es gibt andere Gründe ausser Interesse dafür Verbesserungsvorschläge zu 
posten. Ich helfe meinen Kindern auch das zu lernen woran sie Interesse 
haben. Da mag ich es noch für so uninteressant oder zwecklos halten ...

Nennt man anderen zu helfen.

von Nick M. (Gast)


Lesenswert?

Übrigens berechnet 200! der "TI-enspire CAS" im Bruchteil einer Sekunde.

Gruß,
Nick

von Hagen R. (hagen)


Lesenswert?

Die Software aus obigem Link rechnet 1.000.000! in 800ms auf meinem PC 
aus. Diese Zahl hat 5.565.709 Dezimalstellen.

von Gast (Gast)


Lesenswert?

müdelächel Mein Quantenrechner braucht für 6.022E23! ne Handvoll 
Planckzeiten. Theoretisch zumindest :-)

von Hagen R. (hagen)


Lesenswert?

Tja das ist der Unterschied zwischen Theorie und Praxis ;)

von Altona (Gast)


Lesenswert?

Ihr könntet das ganze jetzt noch rekursiv programmieren.

von Volker Z. (vza)


Lesenswert?

Rekursion sollte mann auf einem µC vermeiden, da hoher Stackbedarf.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.