Logarithmusberechnung

Status
Nicht offen für weitere Antworten.

Knuff

Mitglied
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:

Java:
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

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

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

kirdie

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

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

Und die Schleife würd ich so machen:
Java:
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

Top Contributor
Quadrieren geht auch ohne Math.pow (bzw. mit Math.pow ist es eh eine perverse Verschwendung)
Code:
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

Mitglied
Java:
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

Mitglied
ok...ich hab jetzt mal was versucht:

Java:
  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

Top Contributor
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

Top Contributor
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:
Java:
	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

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

kirdie

Bekanntes Mitglied
ok...ich hab jetzt mal was versucht:

Java:
  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

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:

Java:
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

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

aber: ich bin kein er :noe: ^^
 
C

Chrisi3210xy

Gast
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

Top Contributor
Java:
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;
}
 
Zuletzt bearbeitet:
Status
Nicht offen für weitere Antworten.

Neue Themen


Oben