kleine Frage zu Brüchen



  • So wandele ich ein double in Zähler und Nenner um. Es läuft zwar, aber gibt es einen schnelleren, eleganteren Weg?

    void double_to_bruch(double d)
    {
    	bool neg = false;
    	if (d < 0)
    	{
    		neg = true;
    		d *= -1;
    	}
    	long ganzzahl = static_cast<long>(d);
    	double nachkomma = d - ganzzahl;
    	ostringstream s;
    	s << fixed << nachkomma;
    	string str = s.str();
    	str.erase(0, 2); //0. löschen
    	while (str[str.length()-1] == '0') //hintere Nullen löschen
    		str.erase(str.length()-1, 1);
    	long zaehler = atoi(str.c_str());
    	long nenner = pow(10, str.length());
    	if (ganzzahl != 0)
    		zaehler = ganzzahl * nenner + zaehler;
    	if (neg)
    		zaehler *= -1;
    	cout << zaehler <<"/" << nenner << endl;
    	//das Kürzen geschieht an anderer Stelle
    }
    


  • ich weiß nicht, ob das so richtig ist(also ob es das ist, was du willst), aber mal schaun:

    also du hast eine double zahl... z.b.: 0.75

    das als bruch wäre ja: 0.75 / 1

    nun erweiterst du solange mit 10 bis der Zähler keine nachkommastellen mehr hat... wie man ermitteln kann, ob der Zähler noch nachkommastellen hat, will ich dir überlassen... (es ist doch ein gutes gefühl, wenn man was selber herausfindet...)

    wenn das dann fertig ist, sieht der bruch ja so aus: 75/100
    das musst du dann einfach nur noch kürzen und schon hast du dein: 3/4

    fertig!



  • ist richtig..



  • jup, das geht besser 👍
    Noch n Tipp bitte: 1.9999999999999 soll in 2 umgewandelt werden und nicht in 199999999999/10000000...
    Wie realisiert man das?



  • könntest ja vorher runden..
    z.b. so:

    double round(double inDouble, int stelle)
    {
      inDouble *= pow(10,stelle);
      inDouble += 0.5;
      inDouble = (int)inDouble;
      inDouble /= pow(10,stelle);
      return inDouble;
    }
    

  • Mod

    1.9999999 kann niemals herauskommen. wenn du sie exakt darstellst, endet eine Zahl mit Nachkommastellen, die im binärformat vorliegt, stets auf 5 im dezimal system (bzw. die letzten beiden stellen sind 25 oder 75, wenn wenigstens 2 nachkommastellen da sind usf.)



  • ok, das hab ich mir durch den kopf gehen lassen.
    noch eine frage, ich weiß gar nicht, warum der code mit 0.23 nicht läuft, mit 0.24 aber sehr wohl:

    void double_to_bruch(double d)
    {
    	int z = 0;
    	while (d != long(d)) 
    	{
    		z++;
    		d *= 10;
    	}
    	long zaehler = static_cast<long>(d);
    	long nenner = pow(10, z);
    }
    
    int main()
    {
    	double d = 0.23; //läuft nicht, endlos
         //double d = 0.24; //läuft wie erwartet
    	double_to_bruch(d);
    	return 0;
    }
    

  • Mod

    ohne es getestet zu haben, würde ich sagen, dass du es hier mit einem überlauf problem zu tun hast. double hat 53 signifikante (bit-)stellen, long (auf 32 plattformen) aber nur 32 bits. du brauchst schon einen integer typ, der wenigstens so viele stellen hat wie dein float-typ. also long long oder __int64 etc.



  • kann das die frage des unterschiedes zwischen 0.23 und 0.24 beantworten?



  • Ich hab jetzt das long des obigen Codes in __int64 umgeändert. Jetzt gibts keine Endlosschleife mehr: 0.24 wird sofort in 24 und 100 gewandelt, 0.23 aber wird zu dem Monster 23000000000000004 und 100000000000000000
    Wurde noch nicht gekürzt, ok, aber wie kann ich dieses Aufblähen verhindern?



  • Wie dus verhindern kannst weiß ich nicht, aber das liegt daran, dass 0,23 vmtl. in binär nicht exakt dargestellt werden kann. Wir hatten die diskussion schon öfters, die simple Antwort lautet mehr oder weniger: so einfach geht das nicht. Ich habe vor kurzem (relativ zu betrachten) mal eine Lösung gepostet, die aber nicht getestet war. Sie basierte auf einem unscharfen vergleich und der Annahme, dass long double genauer ist als double. Wenn du willst such ich dirs mal raus. Am einfachsten (aber sich er nicht am schnellsten) geht das wohl über stringstreams...



  • Hm, dann kann ich ja auch bei meinem alten Code ganz oben bleiben, der lief absolut stabil, wenn auch langsam.


  • Mod

    weder .24 noch .23 lassen sich exakt darstellen; theoretisch ergeben beide solche zahlenmonster. das problem ist aber das ständige multiplizieren mit 10, dabei geht genauigkeit verloren. vereinfacht: (hier nur 10stellig)

    0.24: 0.001111010111b (tatsächlich dargestellt: 983/4096)

    *10: 10.01100110011b (9830/4096) es werden aber nur 10 bits gespeichert, also

    10.01100110b
    hier wird also gerundet, und das kann dazu führen, dass der zähler, den du erhälst, sehr klein wird; aber zwingend ist das nicht.


Anmelden zum Antworten