# Java Math.sqrt, Rundungsfehler?



## schlelia (30. Okt 2021)

Hallo,
ich fange gerade erst mit Java an und hab eine Übungsaufgabe bekommen. Es handelt sich um diese Methode:

```
public static double computeAverageSpeed(double t, double m) {
        double a = (8 * PhysicsConstants.BOLTZMANN * t) / (Math.PI * m);
        return Math.sqrt(a); // TODO
    }
```

PhysicsConstants.BOLTZMANN ist einfach 1.380649E-23.

Nun soll es folgenden Test erfüllen:

```
@Test(timeout = 666)
    public void pubTest_computeAverageSpeed_hotOxygen() {
        double molarMass_Oxygen = 0.0319988; // kg/mol
        double expected = 451.54529119983204; // m/s
        double actual = Physics.computeAverageSpeed(PhysicsConstants.NORMTEMPERATURE + 35, molarMass_Oxygen);
        double expectedSimple = expected * Math.sqrt(3 * Math.PI / 8);
        assertTrue(Math.abs(expected - actual) < 1E-4 || Math.abs(expectedSimple - actual) < 1E-4);
    }
```
PhysicsConstants.NORMTEMPERATURE = 273.15
Bei mir funktioniert das noch nicht. Ich verstehe einfach nicht warum, kann mir da jemand helfen?
Danke


----------



## LimDul (30. Okt 2021)

Ohne es mir im Detail anzusehen - Fließkommazahlen sind inhärent ungenau und bei Berechnungen mit derartig vielen Nachkommastellen kommen schnell Abweichungen rein.


----------



## Mart (30. Okt 2021)

alle zahlen können nur binär gespeichert werden dh mit bits werden die dann eingetragen und nachkommastellen machen da immer probleme zb 2.5 gibts nicht exakt in binär das ist dann 2.49888 irgendwas... soweit ich mich richtig erinnere deswegen sind komma zahlen sehr kritisch zu betrachten es passiert aber ansich kein "Fehler"


----------



## Robert Zenz (30. Okt 2021)

schlelia hat gesagt.:


> Hallo,
> ich fange gerade erst mit Java an und hab eine Übungsaufgabe bekommen.



Wie bereits gesagt, Gleitkommazahlen haben bei Definition eine Ungenauigkeit. Daher sollten diese nur verwendet werden wenn man mit der Annaeherung an das eigentlich Ergebnis leben kann (zum Beispiel wenn man eine Grafik zeichent).

Wenn mann ein genaues Ergebnis braucht, oder eine groeszere Genauigkeit als `float`/`double` bietet, kann man in Java BigDecimal verwenden. Hierbei handelt es sich um eine Klasse welche Zahlen mit arbitraerer Genauigkeit darstellen.

Grob umgestellter Code:


```
BigDecimal molarMass_Oxygen = new BigDecimal("0.0319988"); // kg/mol
BigDecimal expected = new BigDecimal("451.54529119983204"); // m/s
BigDecimal actual = Physics.computeAverageSpeed(PhysicsConstants.NORMTEMPERATURE.add(new BigDecimal("35)), molarMass_Oxygen);
BigDecimal expectedSimple = expected.multiply(new BigDecimal("3").multiply(BigDecimal.PI).divide(new BigDecimal("8")).sqrt();
```

Hinweis noch, es gibt einen Unterschied bei den Kosntruktoren von `BigDecimal`:


```
BigDecimal ungenau = new BigDecimal(1.234567); // Nimmt den ungenauen float-Wert.
BigDecimal genau = new BigDecimal("1.234567"); // Nimmt den exakten Wert wie im String.
```


----------



## httpdigest (30. Okt 2021)

expected = 451.54529119983204
expectedSimple = 490.1081088031151
actual = 5.818699625926643E-10

Also eine Abweichung von ca 12 Grössenordnungen!
Das hat _garantiert_ rein gar nichts mit Fließkommaungenauigkeit zu tun.
Meine Vermutung: Deine Rechnung ist einfach komplett falsch oder expected ist nicht das, was rauskommen _soll_.

EDIT: Und Fehler misst man auch eher nicht absolut, sondern relativ. Und das aus eben dem genannten Grund der Fließkommaungenauigkeit. Also Fehler ist nicht einfach der absolute Abstand von actual und expected, sondern der relative, z.B.: abs((actual - expected) / expected) und darauf kann man dann eine gewünschte Abweichung (von z.B. 0,5% oder so) definieren.


----------



## schlelia (31. Okt 2021)

httpdigest hat gesagt.:


> expected = 451.54529119983204
> expectedSimple = 490.1081088031151
> actual = 5.818699625926643E-10
> 
> ...


Aber ich hab genau die Formel angewendet, die gegeben war. https://de.wikipedia.org/wiki/Maxwell-Boltzmann-Verteilung#Mittlere_Geschwindigkeit . Ich habe das schon tausend mal überprüft


----------



## mihe7 (31. Okt 2021)

schlelia hat gesagt.:


> Ich habe das schon tausend mal überprüft


Soweit ich das erkenne, verwendest Du die Formel für die Teilchenmasse, gibst aber die molare Masse rein.


----------



## schlelia (31. Okt 2021)

mihe7 hat gesagt.:


> Soweit ich das erkenne, verwendest Du die Formel für die Teilchenmasse, gibst aber die molare Masse rein.


Diese Formel steht auf dem Aufgabenblatt


----------



## schlelia (31. Okt 2021)

mihe7 hat gesagt.:


> Soweit ich das erkenne, verwendest Du die Formel für die Teilchenmasse, gibst aber die molare Masse rein.


Ich verstehe nicht wie da was komplett anderes bei mir rauskommt. Dann kann ja nur irgendwo eine Einheit nicht passen


----------



## mihe7 (31. Okt 2021)

Wie lautet denn die genaue Aufgabenstellung?


----------



## mihe7 (31. Okt 2021)

schlelia hat gesagt.:


> Ich verstehe nicht wie da was komplett anderes bei mir rauskommt. Dann kann ja nur irgendwo eine Einheit nicht passen


Es liegt daran, was ich oben geschrieben habe. Du bekommst die molare Masse M. Wenn ich das in die Formel für die molare Masse einsetze, erhalte ich als Ergebnis: `Math.sqrt(8*1.380649E-23*6.02214076E23*308.15/(Math.PI*0.0319988))` und damit 451.5453660559818


----------



## schlelia (31. Okt 2021)

mihe7 hat gesagt.:


> Es liegt daran, was ich oben geschrieben habe. Du bekommst die molare Masse M. Wenn ich das in die Formel für die molare Masse einsetze, erhalte ich als Ergebnis: `Math.sqrt(8*1.380649E-23*6.02214076E23*308.15/(Math.PI*0.0319988))` und damit 451.5453660559818


Und woher kommen die 6.02214076E23 genau? Sry dass ich das nicht so verstehe


----------



## mihe7 (31. Okt 2021)

Das ist die Avogadro-Konstante zwecks Umrechnung in Teilchenmasse: M = NA * m <=> m = M/NA, also 1/m = NA/M.

Wenn du in der Formel v=sqrt(8kBT/(πm)) den Term unter der Wurzel betrachtest:


----------

