# runden ohne math! (zur not auch mit)



## dermoritz (12. Jun 2008)

es geht um folgende simple operation die ich gerne so modifizieren würde, dass die double-interne-darstellung-rundungsfehler kompensiert sind - auf deutsch: ich hätte gern das mathematisch korrekte ergebnis.

nun gibt es ja in java.math diverse rundungsfunktionen - geht es auch ohne diese, nur mit den grundrechenarten und rest usw.?

hier der code. was ich dort ausgebe brauche ich im richtigen programm als double aber eben nicht 0.7000..1 sondern 0.7. (wie in dem beispiel)

die 0.02 ist eine variabele, das ganze soll also für alle möglichen anderen faktoren funktionieren. (probiert mal 0.3 ;-))


```
for(int i=0;i<40;i++){
		  System.out.println(i*(double)0.02);
	  }
```


vielen dank im voraus.


----------



## xysawq (12. Jun 2008)

ganz steinzeitlich könnte man auch so runden:

```
double zahl = 12.345;
int temp;

//ohne Nachkommastellen:
temp = (int)(zahl + 0.5);
zahl = (double)temp;

//eine Nachkommastelle
temp = (int)((zahl * 10) + 0.5);
zahl = (double)(temp/10.);

//usw...
```

Das '+ 0.5' ist einfach erklärt, ab .5 wird aufgerundet, hat man also z.b. 12.345 erhält man 12.845, durch den Cast nach int werden die Kommastellen einfach abgeschnitten.
Hat man aber 12.5 (minimale Nachkommazahl zum Aufrunden) und addiert .5 erhält man 13.0...


----------



## Marco13 (12. Jun 2008)

Es ist nicht möglich. Bestimmte Zahlen (wie z.B. schon 0.1) können als double einfach nicht genau dargestellt werden. (Punkt. Daran gibt es nichts zu rütteln und zu runden). Dass es (z.B. auf der Konsole) trotzdem als 0.1 ausgegeben wird, ist vielmehr eine "kline Nettigkeit" der Methode, die eine double-Zahl in einen String umwandelt.


----------



## Baunty (12. Jun 2008)

* EDIT : Die Antwoten wurden bei mir nicht dargestellt die "Lösung" steht schon oben *

Warum nicht Math.round ?

Du kannst die Funktionsweise von Math.round natürlich auch selbst schreiben, ich verstehe nur nicht was dir das bringt.


```
double erg, faktor = 0.3; // Nur als Beispiel
        
        
        for(int i=0; i<40; i++) {
            erg = i * faktor;
            if(erg-(long)erg > 0.5) {
                erg = (long)erg +1;
            }
            else {
                erg = (long)erg;
            }
            System.out.println(erg);
        }
```


----------



## thE_29 (12. Jun 2008)

BigDecimal bietet auch sowas!

mit setScale(ANZAHL_KOMMASTELLEN, BigDecimal.MODUS);


----------



## SlaterB (12. Jun 2008)

Marco13 hat gesagt.:
			
		

> Dass es (z.B. auf der Konsole) trotzdem als 0.1 ausgegeben wird, ist vielmehr eine "kline Nettigkeit" der Methode, die eine double-Zahl in einen String umwandelt.



ich glaube, gegen diese feine Unterscheidung hat der Thread-Ersteller nix, 
dann geht es eben darum, dieses Verhalten zu erzwingen  :


> was ich dort ausgebe brauche ich im richtigen programm als double aber eben nicht 0.7000..1 sondern 0.7. (wie in dem beispiel)



wieso ist die Methode bei 0.7 nicht so nett?


```
public class Test
{

    public static void main(String[] args)
        throws Exception
    {
        for (int i = 0; i < 40; i++)
        {
            double d2 = i * (double)0.02;
            double d = d2 * 100;
            d = (int)(d + 0.5);
            d = d / 100;
            System.out.println(d + " - " + d2);
        }
    }

}
```
funktioniert vorerst, aber kann man dem letzten Schritt, dem /100, immer vertrauen?


----------



## Marco13 (12. Jun 2008)

@SlaterB: Ich wollte da nur einiges grundsätzlich in Frage stellen....



			
				dermoritz hat gesagt.:
			
		

> die 0.02 ist eine variabele, das ganze soll also für alle möglichen anderen faktoren funktionieren. (probiert mal 0.3 ;-))



Und probier' du mal 0.123456789123456789123456789 oder 10e100 :wink:

Wenn es um eine "schöne" Ausgabe geht (und NUR dann, wenn es NUR um die Ausgabe geht!) kann man da ja mit String.format bzw. NumberFormat arbeiten.....


----------



## xysawq (12. Jun 2008)

Also wenn ich das richtig sehe hat SlaterB sowieso nur meine "Lösung" in eine Methode gepackt und nochmal gepostet (ok, ganz leicht umformatiert)...

Und außerdem glaube ich nicht, dass der gute Moritz Zahlen wie 0.123456789123456789123456789 oder 10e100 ausgeben möchte, denn dann wäre er sich auch nicht zu schade 'round' zu importieren


----------



## dermoritz (12. Jun 2008)

danke bis hier hier her. an sowas wie "round" hab ich auch gedacht nur brauch ich die möglichkeit die anzahl der dezimalstellen festzulegen.
und wie gesagt die anzahl der dezimalstellen wird von einer eingabe größe bestimt.

inzwischen hab ich folgendes gemacht:


```
Double factor=0.1;
	  int power_of_ten=(int)Math.ceil(Math.abs(Math.log10(factor)));	
	  for(int i=0;i<40;i++){
		  System.out.println((i*(Math.pow(10,power_of_ten)* factor))/Math.pow(10,power_of_ten));
	  }
```

das erscheint mir aber alles irgendwie zu kompliziert für so eine billige geschichte?! in machen programmiersprachen kann man direkt nach den dezimalstellen einer zahl fragen bzw. beim runden diese festlegen.

da das mit dem runden so ein grundsätzlichen und alltägliches problem ist, sollte es doch ein lösung geben die einfach ist, oder?

(mir ist die problematik mit der internen darstellung klar, aber von einer sprache wie java die einem alles "wegabstrahieren" kann erwarte ich irgendwie auch, dass ich nicht mit der internen darstellung von double/float zahlen rumärgern muss.)


edit:
"bigdecimal" genau sowas suche ich - ein zahelnformat was von ieee-interner darstellung abstrahiert. ich schaus mir mal an...


----------



## dermoritz (12. Jun 2008)

danke the_29 ich hab das mal mit bigdecimal probiert, wunderbar genau nach sowas hab ich gesucht:


```
factor=0.03;
 MathContext mc= new MathContext(2);
 for(int i=0;i<40;i++){
 BigDecimal erg=new BigDecimal(i*factor,mc);	  
 System.out.println(erg.doubleValue());
	  }
```

das....doubleValue() ist nur zum test - ich brauche ja letztendlich einen double. aber mit dem weg über bigdecimal sind sie präzise.


----------

