Funktion gesucht



  • Hallo zusammen,

    ich stehe vor einem Problem, das ich nicht alleine lösen kann. Wahrscheinlich verfüge ich noch nichtmal über den mathematischen Hintergrund, aber ich hoffe, dass ihr mir eine Anleitung geben könnt oder ein Programm vorschlagt, das mein Problem löst.

    Ich suche eine Funktion, die für um 1 ansteigende x folgende Werte ausgibt:

    f(0) = 65
    f(1) = 66
    f(2) = 73
    f(3) = 84
    f(4) = 85
    f(5) = 82
    f(6) = 0
    f(7) = 50
    f(8) = 48
    f(9) = 49
    f(10)= 49

    Ich habe nur Schulwissen und weiß daher nicht, ob es solch eine Funktion überhaupt gibt. Ich könnte durch Rekonstruktion ein Polynom 10. Grades aufstellen, doch da käme ein riesiges Gleichungssytem raus.

    Wie mache so was?

    Danke
    lg, freakC++


  • Mod

    Da kannst du doch alle möglichen Funktionen durch legen. Hast du nicht irgendwelche Nebenbedingungen, was die Funktion sonst noch leisten soll? Interpolations- und Extrapolationsverfahren gibt es viele. Eines davon, was dir vielleicht gefallen dürfte, sind Splines, die du dir mal angucken kannst. Oder wenn man ganz dumm kommt, eine Wertetabelle. Kommt eben drauf an, wozu man die Funktion überhaupt haben möchte.

    Was das Polynom 10. Grades angeht: Du sitzt an einem Computer und schreibst, dass du keine großen Gleichungssysteme lösen magst? 😕



  • Du hast die Funktion doch schon hingeschrieben. 🙂



  • Spaßeshalber habe ich mal das Polynom ausrechnen lassen (z.B. http://www.arndt-bruenner.de/mathe/scripts/gleichungssysteme.htm):

    -   0,0039916777 * x^10
    +   0,1961488646 * x^9
    -   4,1201058201 * x^8
    +  48,3324983466 * x^7
    - 347,1109085648 * x^6
    +1572,8069733796 * x^5
    -4462,3756090168 * x^4
    +7569,5600143298 * x^3
    -6870,3893849206 * x^2
    +2494,1043650794 * x^1
    +  65
    

    wobei ich mir die Koeffizientenmatrix mit einem eigenen Programm habe errechnen lassen:

    1 0 0 0 0 0 0 0 0 0 0 65
    0 1 1 1 1 1 1 1 1 1 1 1
    0 0 2 6 14 30 62 126 254 510 1022 6
    0 0 0 6 36 150 540 1806 5796 18150 55980 -2
    0 0 0 0 24 240 1560 8400 40824 186480 818520 -12
    0 0 0 0 0 120 1800 16800 126000 834120 5103000 32
    0 0 0 0 0 0 720 15120 191520 1905120 16435440 -133
    0 0 0 0 0 0 0 5040 141120 2328480 29635200 601
    0 0 0 0 0 0 0 0 40320 1451520 30240000 -2117
    0 0 0 0 0 0 0 0 0 362880 16329600 5996
    0 0 0 0 0 0 0 0 0 0 3628800 -14485
    


  • Brauchst Du überhaupt andere Werte als f(0) bis f(10) ?

    Wenn nicht, dürfte eine IF ... THEN oder CASE Anweisung eigentlich deutlich effizienter sein.

    Andernfalls kann man durch die von die beschriebenen Punkte sicherlich unendlich viele Funktionen legen. Wenn es aber ein Polynom 10. Grades sein soll, ist das Risiko, dass dies osziliert ziemlich groß, so dass es fraglich ist, ob du mit den anderen Werten der Funktion überhaupt etwas anfangen kannst. Möglicherweise wärst du hier mit SPLINES besser bedient.



  • Hallo zusammen,

    ich habe wie Th69 exakt mit dieser Seite die Berechnung der Koeffizienten durchgeführt.

    Das Problem an einem solchen Polynom ist, dass die Funktion irre lang ist. Da ich keine Ahnung habe was Splines sind, erhoffe ich mir, dass sie eine "kompaktere" Funktion vorschlagen.

    Ich werde mir die Methodik mal anschauen und hoffe, dass ich die auch verstehe 🙂

    Da ich die Funktion bald brauche und zwar in Splines & Co. interressiert bin, aber momentan nicht die Zeit habe, mich da rein zu fragen, benötige ich ein Programm, dass ein schönes Förmelchen ausgibt. Kennt da jemand eins?

    Sonst benutze ich das Polynom 10. Grades 🙂

    Ich danke euch
    lg, freakC++



  • @Th69:Ich habe gerade mal dein Polynom nachgerechnet, aber ohne zu wissen, wo der Fehler liegt, weiß ich, dass nur für f(0) der korrekte Wert geliefert sind. Ab f(2) sind alle Werte total falsch? Siehst Du den Fehler?

    Danke
    lg, freakC++



  • Für was brauchst du die Funktion? Beschreib doch mal, was du genau machen willst und was die Funktion für Eigenschaften haben muss.
    Wenn du nur diese 10 Werte brauchst -> Lookup Table (Wie schon geschrieben wurde).
    Wenn du Zwischenwerte (z.B. f(3.3)) brauchst -> Interpolation. Splines oder Polynome sind eine Variante, evt. reicht dir aber auch lineare Interpolation? Dabei verbindest du zwei benachbarte Punkte mit einer Geraden, deine Funktion ist dann natürlich nicht stetig (sie hat "Ecken") aber oft reicht das schon.
    Wenn du weitere Werte brauchst (z.B. f(20)) -> Extrapolation. Das Polynom wäre hier ungeeignet weil es relativ schnell nach + oder - unendlich wáchst.
    Wenn du damit weiterrechnen willst (Ableiten / Integrieren / was auch immer) -> Schau dir numerische Verfahren an für das was du machen willst... evt. können einige direkt auf deiner Punkteliste arbeiten.
    Wenn du eine einfache Funktion willst, und bereit bist kleine Ungenauigkeiten in Kauf zu nehmen (z.B. f(1)=67 statt 66) -> Ausgleichsrechnung. Du kannst z.B. eine Gerade (oder auch andere Funktionen) durch deine Punkte legen, so dass der Fehler minimal wird. Dazu müsstest du auch eine Idee haben, was du erwartest. Es macht nicht viel Sinn einfach irgendwas durchzulegen...

    Ohne dass du genauer erklärst was du machen willst, können wir dir nicht weiterhelfen. Es gibt unendlich viele Funktionen die durch deine Punkte gehen.



  • lustig schrieb:

    evt. reicht dir aber auch lineare Interpolation? Dabei verbindest du zwei benachbarte Punkte mit einer Geraden, deine Funktion ist dann natürlich nicht stetig (sie hat "Ecken") aber oft reicht das schon.

    Nitpick (aber hier steht "Mathematik" drüber, also...): Sie ist stetig. Sie ist nicht differenzierbar (außer alle Punkte liegen auf einer Geraden).



  • Oops, stimmt. Hast natürlich recht...



  • Hallo,

    das alles ist eigentlich nur ein Spiel. Die oben genannten Zahlen sind der ASCII Code für "Abitur 2011". Diese Werte sollen aber nicht einfach in das Programm eingegeben werden (also kein if...else), sondern durch eine Funktion erhalten werden. Daher ist es mir egal, ob sie nach + / - unendlich abhaut und welche Werte dazwischen liegen. Ich muss sie nur auf überschaubarem Platz implementieren können!

    Ich habe nochmal nachgerechnet, aber mein Polynom ist leider genau so falsch wie das des Th69 😉

    edit: Mit diesen Koeffizienten geht es gut bis zu x=7. Danach wird es wieder sehr falsch 😞

    a = -0,0011983764
    b = 0,0356794186
    c = -0,4230109513
    d = 2,5261147453
    e = -7,7646214585
    f = 10,1947424088
    g = 1,295983848
    h = -12,6432139065
    i = 5,7311643364
    j = 2,0483599357

    lg, freakC++



  • Hallo freakC++,

    dann mußt du falsch gerechnet haben.

    Ich habe es mit meinem MathParser-Beispielprogramm (FctParser) Parser für mathematische Formeln nachgerechnet und bis auf Rundungsfehler kommen die richtigen Funktionswerte raus.
    Hier meine Expression (Punkt anstatt Komma !):

    -0.0039916777 * x^10 + 0.1961488646 * x^9 - 4.1201058201 * x^8 + 48.3324983466 * x^7 - 347.1109085648 * x^6 + 1572.8069733796 * x^5 - 4462.3756090168 * x^4 + 7569.5600143298 * x^3 - 6870.3893849206 * x^2 + 2494.1043650794 * x^1 + 65
    

  • Mod

    Ich schließe, du willst einfach Obfuscation? Wie wäre es damit? Ich war so frei, das Nullzeichen durch eine 32 für Leerzeichen zu ersetzen.

    #include<iostream>
    #include<cmath>
    
    using namespace std;
    
    char getchar(unsigned depth)
    { 
      const unsigned long magic1=117004UL;
      const unsigned long magic2=2576719UL;
      unsigned long magic=magic1;
      if (depth>3){
        depth-=4;
        magic=magic2;
      }
    
      return magic/static_cast<unsigned long>(pow(53, depth)) - 53*(magic/static_cast<unsigned long>(pow(53, depth+1))) + 32;
    }
    
    int main()
    {
      for (unsigned i=0; i<11; ++i) cout << getchar(i);
      cout<<endl;
    }
    

    Leider habe ich nicht alles in eine einzige Zahl bekommen (zumindest ohne den Standard zu verletzen), daher die unschöne Fallabfrage. Wenn du größere Zahlen benutzen kannst (zum Beispiel eine Bib für große Zahlen benutzen) kannst du auch alles in eines packen.

    Das ganze ist ein 53er-System (da 85-32=53) in dem einfach die gewünschten Zahlen minus 32 die depth'ste Stelle sind. Die Formel am Ende ist aus Wikipedia zur Berechnung der depth'sten Stelle einer b-adischen Zahl mit b=53.

    edit: Das Polynom würde ich nicht nehmen, da es numerisch extrem instabil ist. Du musst auf zig-Nachkommastellen genau rechnen, um am Ende die Werte zu treffen, ansonsten liegt das Ergebnis weit daneben.

    edit2: Falls es dein Compiler kann (vermutlich kann er es) ist hier der schönere Code:

    #include<iostream>
    
    using namespace std;
    
    unsigned long long my_pow(unsigned long long base, unsigned exponent)
    {
      unsigned long long result=1;
      for (unsigned i=0; i<exponent; ++i) result*=base;
      return result;
    }
    
    char getchar(unsigned depth)
    { 
      const unsigned long long magic=20331552428843ULL;
      return magic/my_pow(53, depth) - 53*(magic/my_pow(53, depth+1)) + 32;
    }
    
    int main()
    {
      for (unsigned i=0; i<11; ++i) cout << getchar(i);
      cout<<endl;
    }
    

    edit3: Ups, ich habe versehentlich "Abi 2001" statt "Abi 2011" geschrieben. Die Korrektur der Zahlen sollte nicht schwer sein.



  • Du kannst z.B. die Lagrange-Interpolation benutzen. Um das auszurechnen, würde ich aber an deiner Stelle auf maple oder mathematica oder so etwas benutzen. Per Hand macht das sonst ziemlich viel Spass:-).

    Die andere Möglichkeit, Du programmierst den Algorithmus direkt. Das sähe in Java z.B. etwa so aus:

    public class lagrange {
    	lagrange() {
    		for(int i=0; i<11;++i)
    			System.out.println("f("+i+") = " + f(i));	
    	}
    
    	public double f(double x) {
    		double knots[] = {65.0, 66.0, 73.0, 84.0, 85.0, 82.0, 0.0, 80.0, 48.0, 49.0, 49.0};
    		double result = 0.0;
    		double lagrange = 1.0;
    			for(int i=0; i<knots.length;++i) {
    				for(int j=0; j<knots.length;++j) {
    					if(i!=j) 
    						lagrange *= (x - j)/(i - j);						
    				}
    				result += lagrange*knots[i];
    				lagrange =1.0;		
    			}
    		return result;	
    	}
    
    	public static void main(String args[]) {
    		new lagrange();	
    	}
    }
    

    P.S:Im zweifelsfall sollte sich die Funktion f(x) ziemlich leicht in jede andere Programmiersprache übersetzen lassen.



  • nimm doch gnuplot.

    mit einem Interpolationspolynom vom Grad 10 komme ich auf die selben Koeffizienten wie Th69.

    natürlich kann man auch mit raffinierteren Funktionen interpolieren, z.B. mit a*sin(x)+ ... +j*sin(10*x)+k:

    set term postscript
    set output "blub.ps"
    set multiplot
    
    f(x)=a*sin(x)+b*sin(2*x)+c*sin(3*x)+d*sin(4*x)\
    +e*sin(5*x)+f*sin(6*x)+g*sin(7*x)+h*sin(8*x)+i*sin(9*x)+j*sin(10*x)+k
    
    fit f(x) "blub.dat" using 1:2 via a,b,c,d,e,f,g,h,i,j,k
    plot "blub.dat" using 1:2 notitle pointtype 7, f(x)
    


  • Th69 schrieb:

    dann mußt du falsch gerechnet haben.

    Das habe ich! Fehler beseitigt!

    SeppJ schrieb:

    Ich schließe, du willst einfach Obfuscation?

    Du bist Hellseher!? Ja, genau das möchte ich haben 🤡 ! Dein Codeschnipsel gefällt mir aber sehr! Doch ich kann ihn nicht so ganz nachvollziehen.

    Ich habe von Obfuscation nicht nie was gehört! DAs ist aber hammer cool! Danke auch an alle anderen! Ich denke aber, dass ich SeppJs Vorschlag nehme (sobald ich ihn verstanden habe) 😃

    edit: Rest gelöscht, weil ich mir selber nicht einig war, was ich erst fragen soll! 🙂

    Vielen Dank
    lg, freakC++



  • Ich erstelle lieber noch einen neuen Post, bevor ich den Rekord der meisten Änderungen knacke!

    Ich habe mich ein bisschen informiert! SeppJ hat anscheinend die Formel der Wikipedia Seite "Stellenwertsystem" genutzt. Diese habe ich nun auch gefunden.

    Mir sind jetzt eigentlich nur drei Sachen nicht klar.

    1.) Welche Aufgabe hat "magic" und wie errechne ich diese Zahl?

    2.) Ist das Stellensystem 53 beliebig oder hat es einen Grund, warum Du dich dafür entschieden hast?

    3.) Warum kommen gerade die Zahlen heraus, die ich gerne hätte, wenn ich x mit 1 inkrementiere. Warum erscheint gerade die Folge 65, 66, 73....?

    Danke
    lg, freakC++


  • Mod

    freakC++ schrieb:

    1.)

    magic1=117004UL;
      const unsigned long magic2=2576719UL;
    

    Was sind das für Zahlen und wie kommst Du darauf?

    Das ist vielleicht einfacher an dem zweiten Codeschnipsel nachzuvollziehen:

    20331552428843 = (65-32)*53^0 +
                     (66-32)*53^1 +
                     (73-32)*53^2 +
                     (32-32)*53^3 +
                     (50-32)*53^4 +
                     (48-32)*53^5 +
                     (48-32)*53^6 +
                     (49-32)*53^7
    

    Und da ich mich bei der vorletzten Zeile vertan habe (da sollte ja eigentlich eine 49 statt 48 stehen) kommt ABI 2001 und nicht ABI 2011 raus, aber das kannst du ja leicht ändern.
    Wenn du "ABITUR 2011" willst, musst du entsprechen noch was dazwischen fügen. Da 53^11 < 2^64 sollte das aber noch gehen, vorausgesetzt ein long long ist bei dir ebenfalls (mindestens) 64 Bit groß.

    Die beiden kleineren Zahlen sind jeweils

    117004 = (65-32)*53^0 +
             (66-32)*53^1 +
             (73-32)*53^2 +
             (32-32)*53^3
    

    und

    2576719 = (50-32)*53^0 +
              (48-32)*53^1 +
              (48-32)*53^2 +
              (49-32)*53^3
    

    da ich sonst nicht genug Platz hatte, wenn ich mich streng an die Mindestgröße eines long im C++-Standard halte.

    2.) Du sprichst von einem 53er-System mit der Begründung 85-32=53!!

    Da ich die 0 durch eine 32 ersetzt habe, hast du Werte zwischen 32 (für das Leerzeichen) und 85 (für das U). Um Platz zu sparen, kann ich daher immer erst 32 abziehen und erhalte dann maximal Werte bis 53 (siehe Rechnung oben). ⚠ Und hier finde ich auch einen Fehler bei mir: Damit "Ziffern" in meinem Zahlensystem Werte zwischen 0 und 53 haben können, müsste ich ein 54er System nehmen. Die Rechnung muss dementsprechend geändert werden, wenn du "ABITUR 2011" haben willst.

    Ich habe nach der sogenannten "depth'sten" Zahl gegoogelt, aber man findet gar nichts. Was ist das? Wie kommst Du auf 32? Und was macht "depth"?

    Ja, depth ist ein schlechter Bezeichner. Wollte das Programm ursprünglich rekursiv machen. Aber so wie es jetzt ist, sollte ich das depth wohl eher N nennen. Das get_char liefert dann die N'te Stelle der Zahl magic im 53er-System.

    3.) Welchen Wikipedia Artikel meinst Du?

    Die Formel findet man hier:
    http://de.wikipedia.org/wiki/Stellenwertsystem#Formeln_f.C3.BCr_Ziffern_und_Operationen_mit_Ziffern

    Für b habe ich 53 (Die Basis des Zahlensystems), x ist das magic also die Zahl deren Stelle man wissen will und k ist das depth, also die wievielte Stelle man wissen will.

    4.) Ich muss gestehen, dass ich Abi 2001 nicht in "Abitur 2011" umwandeln kann. Das liegt daran, dass momentan da noch nicht so richtig durchblicke! Ich verstehe nicht, wie die Buchstaben erzeugt werden!

    Mit der ausführlichen Rechnung oben sollte das klappen. Wenn du Schwierigkeiten hast, sag Bescheid. Du wirst aber einen guten Taschenrechner brauchen, Google calc stellt solch große Zahlen nicht mehr exakt dar. Wolfram Alpha sollte das können oder auch jedes etwas bessere Rechenprogramm auf deinem Computer. Oder ein selbst geschriebenes Programm.
    Und falls die Zahlen zu groß werden ("ABITUR 2011" sollte gehen, aber "Abitur 2011" ist zu groß für 64-Bit longs), musst du eventuell auf eine BigInt Bibliothek ausweichen.



  • Ich danke dir! Ich werde nun einiges ausprobieren und mich dann nochmal melden!

    lg, freakC++



  • Mir ist noch nicht ganz klar, warum Du gerade 32 als Leerzeichen gewählt hast. Wenn ich beispielsweise 20 als Leerzeichen nehme, dann kann ich auch ein 65 System nehmen, oder?

    lg, freakC++


Anmelden zum Antworten