# Logarithmusberechnung



## Knuff (16. Nov 2009)

Hallo Leute!
Ich bin neu hier und brauche unbedingt Hilfe, weil ich einfach nicht weiterkomme.
Die bisherigen Aufgaben in Programmierung waren relativ leicht zu lösen.
Wäre total nett, wenn mir jemand weiterhelfen könnte!

Hier die Aufgabe, die ich lösen soll:

Logarithmus.java. Für x > 0 kann ln x nach der Formel

ln x = 2 * [(x-1)/(x+1) + (x-1)^3/3*(x+1)^3 + (x-1)^5/5*(x+1)^5 + ... +(x-1)^(2n+1)/(2n+1)(x+1)^(2n+1)  + ...]

(leider weiß ich nicht, wie ich die Formel lesbarer schreiben kann)

näherungsweise berechnet werden. Schreiben Sie ein Java-Programm, das vom Nutzer eine Zahl x > 1 abfragt und einen Näherungswert für ln x am Bildschirm ausgibt. Sie können sich ohne Test daraus verlassen, dass x > 1 (also x - 1 > 0) gilt. Die Berechnung soll abbrechen, sobald sich die Näherungswerte der aktuellen und vorigen Iteration (also die Werte für n+1 bzw. n Summanden) um weniger als 10^-7 unterscheiden.
In der Lösung dürfen nur die bereits behandelten Sprachkunstrukte von Java verwendet werden (also Schleifen, Verzweigungen, Gleitkommazahlen, Methoden..), _keine_ Bibkliotheksfunktionen wie Math.pow.

So, also angefangen hab ich so:


```
class Logarithmus {

  public static void main(String[] arg) {
    Out.print("Bitte geben Sie eine Zahl ein: ");
    double zahl = In.readDouble();
    Out.println("Naeherungswert fuer ln(" + zahl + "): " + berechneLogarithmus(zahl));
  }
  static double berechneLogarithmus(double x){
```

und ich weiß, dass ich zum Berechnen eine Schleife brauche. Aber wie mache ich jetzt weiter? Ich muss ja auch irgendwie die Hochzahlen hinbekommen und das mit dem Abbrechen...???:L
Ich steh total aufm Schlauch.
Wäre gut, wenn mir schnell wer antworten würde, da ich die Aufgabe morgend Abend fertig haben muss. Danke schonmal.

Knuff


----------



## Marco13 (16. Nov 2009)

Hochzahlen mit
double result = Math.pow(basis, exponent);

Schleife abbrechen... sowas wie [c]if (ergebnisIstGenauGenug) break;[/c]...


----------



## Michael... (16. Nov 2009)

Identisches Thema wurde vor kurzem unter etwas anderem Aspekt hier schon mal behandelt. Vielleicht steht da ja was hilfreiches drin:
http://www.java-forum.org/java-basics-anfaenger-themen/91224-double-bestimmte-nachkommzahl-vergleichen-ohne-zusaetzliche-libs.html#post577480


----------



## kirdie (16. Nov 2009)

Also wenn du Math.pow() nicht benutzen kannst, dann würd ich mir zuerst selbst eine schreiben:


```
double myPow(double base, int exponent)
{
double ergebnis = [...]
return ergebnis;
}
```

Und die Schleife würd ich so machen:

```
static double berechneLogarithmus(double x, int stufe)
{
	// berechne das ergebnis mit <stufe> additionstermen
}
static double berechneLogarithmus(double x)
{
	int stufe = 1;
	double ergebnis;
	double letztesErgebnis;
	do
	{
		[...]
	}
	while(ergebnisse zu unterschiedlich);
      return ergebnis;
}
```


----------



## 0x7F800000 (16. Nov 2009)

Quadrieren geht auch ohne Math.pow (bzw. mit Math.pow ist es eh eine perverse Verschwendung)

```
x*x
```
und mehr als quadrieren brauchst du hier nicht, da sich die aufeinanderfolgende summanden immer um quadrate irgendwelcher terme unterscheiden, du musst die eben abspeichern und weiterverwenden.


----------



## Knuff (16. Nov 2009)

```
double myPow(double base, int exponent)
{
double ergebnis = [...]
return ergebnis;
}
```

meinst du damit, dass ich das erstmal allgemein schreibe, also praktisch was Math.pow() bedeutet oder soll das gleich auf zur Aufgabe passen?


----------



## Knuff (16. Nov 2009)

ok...ich hab jetzt mal was versucht:


```
static double myPow(double base, int exponent){ 
    double ergebnis = base;
    for(int i = 1; i <= exponent; i++){
      if(exponent = 1){
          ergebnis = base; break;
        } else 
        ergebnis *= base;
      }
      return ergebnis;
  }
```

war sowas gemeint, oder is das komplett falsch????:L


----------



## Marco13 (16. Nov 2009)

Das ist "richtig" - so richtig wie etwas sein kann, was grooottenlangsam ist, und viel schneller gemacht werden könnte (Websuche: "Schnelle Exponentiation"). MUSST du pow überhaupt selbst implementieren?

Ich habe die Formel aber nicht nachvollzogen - deswegen gehe ich mal davon aus, dass Andrey recht hat, und man sich das pow durch geschicktes Speichern von Zwischenergebnissen auch ganz sparen kann.


----------



## 0x7F800000 (16. Nov 2009)

Marco13 hat gesagt.:


> Das ist "richtig" - so richtig wie etwas sein kann, was grooottenlangsam ist, und viel schneller gemacht werden könnte (Websuche: "Schnelle Exponentiation"). MUSST du pow überhaupt selbst implementieren?


Der Algo ist sooo niedlich:

```
public static double sq(double x){
		return x*x;
	}
	
	public static double pow(double base, int exp){
		return exp>0?sq(pow(base,exp/2))*(exp%2==1?base:1):1;
	}
```
Aber man braucht das hier wirklich nicht, damit würde man das Programm nur unnötig länger und unnötig langsamer machen.


----------



## Marco13 (16. Nov 2009)

In solchen Fällen sollte man seinen Variablen und Methoden aber die Namen i,í,ì,î,I,Í,Ì,Î und l geben, damit sich's lohnt


----------



## kirdie (17. Nov 2009)

Knuff hat gesagt.:


> ok...ich hab jetzt mal was versucht:
> 
> 
> ```
> ...



Genau, da ist aber noch ein kleiner Fehler drin. Wenn ich mich nicht irre berechnet deine Prozedur:
- base, falls exponent <= 1, 
- base^(exponent+1), falls exponent > 1

Stell dir mal den Programmablauf vor (oder benutze einen Debugger), wenn du exponent = 2 setzt, dann wird die Schleife zweimal durchlaufen.
Die ausgeführten Zuweisungen sind dann:
ergebnis = base;
ergebnis*=base;
ergebnis*=base;

Damit kommt dann base^3 raus und nicht base^2.

Beheben würde ich das so:


```
static double myPow(double base, int exponent){ 
    double ergebnis = 1;
    for(int i = 1; i <= exponent; i++) ergebnis *= base;
      return ergebnis;
  }
```

Aber das man sich die Potenzierungen sparen kann, indem man die Zwischenergebnisse benutzt ist natürlich auch cool.
Das weist natürlich darauf hin, dass der Prof vielleicht wirklich das gemeint hat, dass man das so löst.
Aber da er ja nicht verboten hat, selbst eine Pow-Funktion zu implementieren, geht es so sicherlich einfacher. Ist zwar nicht so elegant oder schnell, aber wenn du so schon Probleme hast das überhaupt hinzukriegen ist das ja nebensächlich.
Und du kannst die Funktion für spätere Aufgaben verwenden, bei denen du keine Math-Bibliothek verwenden darfst 

@Die anderen:
Wenn er die Aufgabe so schon kaum schafft, nützt es doch garnix, ihn jetzt mit irgendwelchen Optimierungen zu verwirren. Das er pow nicht verwenden darf, steht auf dem Aufgabenblatt (ImageBanana - Aufgabe.jpg, hat "evil" zeitgleich gepostet).


----------



## Knuff (17. Nov 2009)

danke kirdie  jetzt krieg ichs bestimmt hin.
jetzt bin ich nicht mehr so verwirrt.

aber: ich bin kein er :noe: ^^


----------



## Chrisi3210xy (18. Aug 2012)

Wie wär es damit?:
[Java]
public static double ln(double x){
		int i;
	    double sum=0;
	    double sumerg=0;
	    double xk=0;
	    boolean b=false;

	    if (x<=0)  sumerg=Double.NaN;
	    if ((x>0)&&(x<1)){
	     xk=x-1;
	     sum=xk;
	     sumerg=xk;
	     i=2;

	     while(sum!=0){
	      sum=sum*xk/i;


	      if(b){
	       sumerg=sumerg+sum;b=false;	  
	      }
	      else{
	       sumerg=sumerg-sum;b=true;	 
	      }
	      i++;
	     }

	    }

	    if (x==1) sumerg= 0.0;
	    if (x>1) sumerg=-ln(1/x);
	    return sumerg;	
	} 
[/code]


----------



## Landei (19. Aug 2012)

```
private static final double EPSILON = 0.00000001;

private static double ln(double x) {
    assert x > 1;
    double a = x-1;
    double b = x+1;
    double aFactor = a*a;
    double bFactor = b*b;
    double delta = 1;
    double result = 0;
    for(int i = 1; delta > EPSILON; i+=2) {
        delta = a/b/i;
        result += delta;
        a *= aFactor;
        b *= bFactor;
    }
    return 2*result;
}
```


----------

