matze511: rechnen mit Winkelfunktionen

Hallo liebe Profis,

ich stehe vor einem Problem mit den Winkelfunktionen bei dem rechtwinkligen Dreieck. Ich habe hier ein kleines JavaScript:


	function addieren() {
		grundmaß = parseFloat(document.getElementById('grundmaß').value.replace(',', '.'));
		dachneigung = parseFloat(document.getElementById('dachneigung').value.replace(',', '.'));
		dachüberstand = parseFloat(document.getElementById('dachüberstand').value.replace(',', '.'));
		traufhöhe = parseFloat(document.getElementById('traufhöhe').value.replace(',', '.'));
		fußpfettenrücksprung = parseFloat(document.getElementById('fußpfettenrücksprung').value.replace(',', '.'));
		raumhöheRohbau = parseFloat(document.getElementById('raumhöheRohbau').value.replace(',', '.'));
		
		firsthöhe = parseFloat(((grundmaß + dachüberstand) * (Math.tan(dachneigung))).toPrecision(4));
		
		document.getElementById('firsthöhe').value = firsthöhe;
	}

Wenn ich jetzt für Grundmaß 5,00 einsetze, für Dachüberstand 0,50 und für Dachneigung 30° dann gibt es mir -35.23 aus. Die richtige Lösung laut den Winkelsätzen wäre aber 3,175, wo hab ich hier den Denkfehler?

LG matze

  1. @@matze511

    Dachneigung 30°

    Das gibts du wie an? Als Wert 30?

    wo hab ich hier den Denkfehler?

    Vermutlich an der Stelle, wo du denkst, Winkelfunktionen würden als Argument den Winkel in Grad erwarten. Tun sie aber nicht, sondern im Bogenmaß (Radiant).

    Kwakoni Yiquan

    --
    Ad astra per aspera
    1. Also heißt das ich muß im Vorfeld noch eine Funktion haben, die den Wert errechnet.

      const degreesToRads = deg => (deg * Math.PI) / 180.0;
      
      degreesToRads(90.0); // ~1.5708
      

      oder geht das auch alles in einem?

      1. @@matze511

        const degreesToRads = deg => (deg * Math.PI) / 180.0;
        
        degreesToRads(90.0); // ~1.5708
        

        Warum 180.0 und 90.0? JavaScript ist nicht C, wo man ganzzahlige Werte nicht auch ohne Nachkommaanteil als Fließkommazahlen verwenden kann.

        oder geht das auch alles in einem?

        firsthöhe = (grundmaß + dachüberstand) * Math.tan(dachneigung * Math.PI/180);
        

        Oder wie @Rolf B sagte: dachneigung gleich beim Einlesen in Radiant umrechnen.

        firsthöhe würde ich hier als Zahlenwert belassen, nicht in einen String umwandeln. Das Runden auf die gewünschte Anzahl von Nachkommastellen geschieht erst bei der Ausgabe, nicht schon bei der Berechnung.

        Kwakoni Yiquan

        --
        Ad astra per aspera
        1. @@Gunnar Bittersmann

          Oder wie @Rolf B sagte

          Ist hier was kaputt? Warum wird die @-Erwähnung nicht zu einem Link aufgelöst?

          Edit: Huch, auf einmal geht’s wieder.

          Kwakoni Yiquan

          --
          Ad astra per aspera
  2. Hallo matze511,

    abgesehen von den Winkeleinheiten, die Gunnar benannte, hätte ich folgende Anmerkungen:

    • die Funktion heißt addieren, tut aber nachweislich mehr als das. Ich sehe eine Multiplikation und einen Tangens. Benenne deine Funktionen so, dass ihr Zweck aus dem Namen ersichtlich ist.

    • Du deklariest deine Variablen nicht. Damit werden globale Variablen daraus, die ihren Wert auch behalten, wenn die Funktion beendet ist. Ich bin sicher, dass das nicht deine Absicht ist. Verwende const, wenn du der Variablen nur einmal einen Wert zuweist und sie dann ihren Wert behält, oder let, wenn Du während eines Funktionsdurchlaufs den Wert zuweisen und nochmal ändern musst.

    // so
       const grundmaß = parseFloat(...);
    // oder so
       let grundmaß = parseFloat(...);
    
    • Du liest den value aus den Eingabefeldern. Sind das Texteingabefelder? Wenn ja, dann musst Du das so tun, ABER du hast auch das Problem, dass die Eingabewerte möglicherweise keine Float-Zahl darstellen. D.h. parseFloat liefert Dir eventuell NaN (not a number). Damit weiterzurechnen führt am Ende zu NaN in der firsthöhe, und das möchtest Du nicht im Ausgabefeld sehen. Frage also mit isNaN() ab, ob du eine gültige Zahl hast.
      Oder besser: probiere input type="number" aus. Setze den step-Wert so, dass die Zahl der Nachkommastellen für den Sachverhalt passt. Dann kannst Du den Eingabewert mit valueAsNumber statt value abholen und hast gleich eine Zahl. Die Frage "Dezimalkomma oder Dezimalpunkt" löst dann der Browser für Dich.

    • Du klammerst Math.tan(wert) ein. Das ist nicht kein Fehler, aber unnötig

    • Du berechnest die Firsthöhe mit einer Formel. Auf das Ergebnis wendest Du toPrecision(4) an, um auf 4 Nachkommastellen zu runden, dann machst Du mit parseFloat() wieder eine Zahl daraus. Wenn es Dir nur um die gerundete Darstellung geht, dann lass das parseFloat weg. Wenn du mit dem gerundeten Wert weiterrechnen willst, dann - ja - hast Du eine fehlendes JavaScript-Feature gefunden: Runden auf N Nachkommastellen. Ob man nun mit parseFloat(x.toPrecision(4)) arbeitet oder mit Math.round(x*10000)/10000, ist wohl eher egal. Aber wenn Du das öfter tun musst, schreib Dir eine Funktion. Das ist zwar mehr Code, aber weniger Rechenaufwand für den Computer.

    function runden(wert, stellen = 0) {
       const skalierung = 10 ** stellen;
       return Math.round(wert * skalierung) / skalierung;
    }
    
    • Ein Grundprinzip der Programmierung heißt DRY (Don't Repeat Yourself). Das tust Du aber reichlich. Schreibe Dir eine Hilfsfunktion, um einen Float-Wert aus einem Eingabefeld zu bekommen, wenn Du bei input type="text" bleiben willst:
    function getFloatValue(id) {
       const element = document.getElementById(id);
       if (element)
          return parseFloat(element.value.replace(',', '.'));
       else
          return NaN;
    }
    
    function berechnen() {
       const grundmaß       = getFloatValue('grundmaß'),
             dachneigung    = getFloatValue('dachneigung') / 180 * Math.PI, 
             ...
             raumhöheRohbau = getFloatValue('raumhöheRohbau');
    
       const firsthöhe = (grundmaß + dachüberstand) * Math.tan(dachneigung);
    
       document.getElementById('firsthöhe').value = firsthöhe.toPrecision(4);
    }
    

    Die Dachneigung rechne ich gleich beim Auslesen ins Bogenmaß um.

    Beachte in dem mehrzeiligen const: jede Deklaration endet mit einem Komma, außer der letzten, da muss das Semikolon stehen, dass das Statement beendet

    Wegen der Verwendung von toPrecision: siehe weiter oben…

    Rolf

    --
    sumpsi - posui - obstruxi
    1. Hallo und erstmal vielen dank für die ausführliche Antwort! Besteht auch die Möglichkeit das sofort nach Eingabe selber rechnet ohne das ich einen Button drücken muss?

      1. Hallo

        Hallo und erstmal vielen dank für die ausführliche Antwort! Besteht auch die Möglichkeit das sofort nach Eingabe selber rechnet ohne das ich einen Button drücken muss?

        Du kannst für das Eingabefeld einen Eventhandler „change“ definieren. Der wird bei jeder Änderung des Inhalts des Eingabefelds ausgelöst. Die Frage, was du mit dem Zwischenstand tust - die Eingabe muss in diesem Moment ja nicht vollständig sein –, sei aber gestattet. Im Zweifelsfall ist der Eventhandler „blur“ besser geeignet, der ausgeführt wird, wenn das Element/das Eingabefeld den Fokus verliert, also dann, wenn die Eingabe (mutmaßlich) fertig ist und ein anderes Feld fokussiert wird.

        Tschö, Auge

        --
        „Habe ich mir das nur eingebildet, oder kann der kleine Hund wirklich sprechen?“ fragte Schnapper. „Er behauptet, nicht dazu imstande zu sein“ erwiderte Victor. Schnapper zögerte (…) „Nun …“ sagte er schließlich, „ich schätze, er muss es am besten wissen.“ Terry Prattchett, Voll im Bilde
        1. @@Auge

          Hallo und erstmal vielen dank für die ausführliche Antwort! Besteht auch die Möglichkeit das sofort nach Eingabe selber rechnet ohne das ich einen Button drücken muss?

          Du kannst für das Eingabefeld einen Eventhandler „change“ definieren. Der wird bei jeder Änderung des Inhalts des Eingabefelds ausgelöst.

          Nein, wird er nicht. Das hast du wohl mit dem input-Event verwechselt? ☞ Codepen

          Im Zweifelsfall ist der Eventhandler „blur“ besser geeignet, der ausgeführt wird, wenn das Element/das Eingabefeld den Fokus verliert, also dann, wenn die Eingabe (mutmaßlich) fertig ist und ein anderes Feld fokussiert wird.

          Nö, blur ist nicht so gut geeignet. Das feuert nicht bei den Pfeiltasten.

          Besser geeignet ist change. ☞ Codepen

          Kwakoni Yiquan

          --
          Ad astra per aspera
          1. Hallo

            Im Zweifelsfall ist der Eventhandler „blur“ besser geeignet, der ausgeführt wird, wenn das Element/das Eingabefeld den Fokus verliert, also dann, wenn die Eingabe (mutmaßlich) fertig ist und ein anderes Feld fokussiert wird.

            Nö, blur ist nicht so gut geeignet. Das feuert nicht bei den Pfeiltasten.

            Warum sollte es auch, wenn ich doch mit den Pfeiltasten nur den Cursor innerhalb des Feldes bewege, dieses aber nicht verlasse (wobei dann „blur“ ausgelöst würde)?

            Tschö, Auge

            --
            „Habe ich mir das nur eingebildet, oder kann der kleine Hund wirklich sprechen?“ fragte Schnapper. „Er behauptet, nicht dazu imstande zu sein“ erwiderte Victor. Schnapper zögerte (…) „Nun …“ sagte er schließlich, „ich schätze, er muss es am besten wissen.“ Terry Prattchett, Voll im Bilde
        2. Hallo Auge,

          change feuert bei Tastatureingaben auch erst, wenn das Input-Feld den Focus verliert. input feuert dagegen bei jedem Tastendruck. Wenn man da 123 eingibt, wird erst für 1, dann für 12 und dann erst für 123 gerechnet. Wenn das stört, muss man das Ausführen des Eventhandlers verzögern.

          Ich habe schon beides gemacht: bei change habe ich einen OK-Button plaziert, dessen einzige Aufgabe war, den Usern etwas zum draufklicken zu bieten, statt "Klicken Sie irgendwo hin".

          Bei meinem Energierechner verwende ich inzwischen ein verzögertes Input-Event und lese die <input type="number> mit valueAsNumber aus.

          Gruß
          Jürgen

    2. Hallo Rolf,

      das hat alles wunderbar geklappt aber nun steh ich wieder vor einem Problem, wie kann ich es anstellen das es eine Rechnung nach der anderen Ausführt, da es mehrere Rechnungen für das Endergebnis sind. Ach und wie speichert man werte die nirgends auf der Webseite auftauchen da sie nur zum rechnen sind?

        function getFloatValue(id) {
      		const element = document.getElementById(id);
      		if (element)
      		return parseFloat(element.value.replace(',', '.'));
      		else
      		return NaN;
      }
      
      	function traufhöVordachNeigung() {
      		let 	grundmaß      	= getFloatValue('grundmaß'),
      				dachneigung    	= getFloatValue('dachneigung') / 180 * Math.PI, 
      				dachüberstand	= getFloatValue('dachüberstand')
      				traufhöhe		= getFloatValue('traufhöhe')
      				raumhöheRohbau 	= getFloatValue('raumhöheRohbau'),
      				//firsthöhe		= getFloatValue('firsthöhe'),
      				okFußpfette		= getFloatValue('okFußpfette'),
      				okFirstpfette	= getFloatValue('okFirstpfette');
      
      		let firsthöhe 	= (grundmaß + dachüberstand) * Math.tan(dachneigung) + traufhöhe,
      		let okKniestock = (dachüberstand* Math.tan(Dachneigung)),
              let lotrechtesObholz = (sparrenhöhe - klauentiefe) / Math.cos(dachneigung);
       
      		document.getElementById('firsthöhe').value = firsthöhe.toPrecision(4),
      		document.getElementById('okKniestock').value = okKniestock.toPrecision(4),
      		document.getElementById('lotrechtesObholz').value = lotrechtesObholz.toPrecision(4);
      

      LG matze

      1. Hallo matze,

        ich verstehe deine Fragen nicht.

        Die Anweisungen in Javascript werden - innerhalb einer Funktion - nacheinander ausgeführt (unter Berücksichtigung von Abfragen und schleifen, natürlich).

        Funktionen laufen in der Reihenfolge, wie sie aufgerufen werden.

        Wie wird denn derzeit deine Traufhöhevordachneigung-Funktion aufgerufen?

        Rolf

        --
        sumpsi - posui - obstruxi
      2. Hallo Namensvetter!

        @JürgenB hatte Dir schon vor 2 Wochen geschrieben:

        du wirst nicht umhin kommen, HTML und Javascript zu lernen. Aber dafür haben wir einiges in unserem Wiki:

        • Wie fange ich an, und da speziell der Einstieg in HTML und der Einstieg in Javascript.
        • Für deine Rechnungen brauchst du das Math-Objekt .
        • Ein Beispiel für Eingabe, Berechnung und Ausgabe von Zahlen: BMI-Rechner

        Fang mal an und wenn du nicht weiter weißt, frag hier nach.

        Diesem Rat kann ich mich nur anschließen! Frag, wenn etwas nicht funktioniert!

        Herzliche Grüße

        Matthias Scharwies

        --
        Was ist eine Signatur?