C: Reelle Zahlen im Exponenten

Hallo,

ich habe folgendes Problem: Ich würde gerne eine Reihe von elektrischen Widerständen aus der E24-Reihe ausrechnen. Die Formel dazu ist:

10^(i/24)

wobei i für den i-ten Widerstand steht.

Leider kann die Funktion pow() keine reellen Exponenten. Ich habe also versucht, das Problem zu umgehen und folgende Funktion geschrieben:

return exp( log(i/24) * log(10.0) );

Dabei ist mir aufgefallen, daß die Funktion exp ganz komische Werte ausrechnet. Jedenfalls rechnet es an meinem einen Computer nur mit int-Werten richtig, nicht aber mit double. Auf einem anderen Computer rechnet es niemals richtig. Ich frage mich, was ich falsch mache.

Im folgenden findet Ihr den gesamten Quelltext. Das Programm wird kompiliert mit „gcc -lm Widerstandsberechnung.c“. Der Fehler ist mit der ersten Funktion namens double Widerstand(int i) verknüpft.

Wäre echt toll, wenn mir jemand einen Hinweis geben könnte.

Viele Grüße!

Bernhard

Hier das Programm:

/** Dieses Programm rechnet zwei Widerstandswerte aus, die in Serie verschaltet
dem gesuchten Widerstandswert am ehesten entsprechen. */

#include
#include

#define E_REIHE 24

// Folgende Funktion berechnet den i-ten Widerstand der E-Reihe.
double
Widerstand(int i)
{
double power;
power = i/E_REIHE;
return exp( log(power) * log(10.0) ); // Berechnet 10^(i/E_Reihe), z.B. 10^(i/24)
}

int
main()
{
// Variablendeklaration
unsigned int i, j;
long int GesuchterWert, Gesamtwiderstand, BesterWert = 600000, ErsterWiderstand, ZweiterWiderstand;

// Abfrage, welcher Wert gesucht ist:
printf („Welcher Widerstandswert ist gesucht? „);
scanf (“%d“, &GesuchterWert);

// Berechnung der beiden besten WiderstŠnde
for (i=0; i

Auch hallo.

ich habe folgendes Problem: Ich würde gerne eine Reihe von
elektrischen Widerständen aus der E24-Reihe ausrechnen. Die
Formel dazu ist:

10^(i/24)

wobei i für den i-ten Widerstand steht.

Leider kann die Funktion pow() keine reellen Exponenten. Ich
habe also versucht, das Problem zu umgehen und folgende
Funktion geschrieben:

return exp( log(i/24) * log(10.0) );

Dabei ist mir aufgefallen, daß die Funktion exp ganz komische
Werte ausrechnet. Jedenfalls rechnet es an meinem einen
Computer nur mit int-Werten richtig, nicht aber mit double.
Auf einem anderen Computer rechnet es niemals richtig. Ich
frage mich, was ich falsch mache.

Zum Vergleich: XP (32 Bit) + SP2, AMD 3000+, MS Visual Studio 6.0
Es kann also an der Hardware und damit verbunden an den Datentypen hängen.

Wäre echt toll, wenn mir jemand einen Hinweis geben könnte.

Interessant: die Programmergebnisse lassen sich auf DOS Ebene via ‚widerstand > widerstand.txt‘ und Angabe einer Zahl gefolgt von Enter in eine txt-Datei speisen. Et voila (Eingabe war 56): http://mitglied.lycos.de/schachspielen/widerstand.txt
Einige Konvertierungen wurden übrigens bemängelt: http://mitglied.lycos.de/schachspielen/www_widerstan…

Aber mal doof gefragt: was soll eigentlich für beliebige Eingaben herauskommen ?

mfg M.L.

Hallo Bernhard,

Leider kann die Funktion pow() keine reellen Exponenten.

Falsch. pow kann schon reelle, aber keine
komplexen Exponenten :wink:

 printf("%f", pow(9, 0.5));
 ==\>
 3

double Widerstand(int i) {
double power;
power = i/E_REIHE;

Fehler:
implizite Konvertierung zu double in
der Operation, wenn ein Operand double ist!

 power = (double)i/E\_REIHE; 

oder

 #define E\_REIHE 24<u>.0</u>

Überprüfe bitte mal Dein restliches
Programm sukzessive. Dann klappt auch das,
was Du möchtest :wink:

Grüße

CMБ

Juhuu! Alles Super! Hier das korrekte Programm
Hallo Semjon, hallo Markus,

Leider kann die Funktion pow() keine reellen Exponenten.

Falsch. pow kann schon reelle, aber keine
komplexen Exponenten :wink:

printf("%f", pow(9, 0.5));
==>
3

double Widerstand(int i) {
double power;
power = i/E_REIHE;

Fehler:
implizite Konvertierung zu double in
der Operation, wenn ein Operand double ist!

power = (double)i/E_REIHE;

oder

#define
E_REIHE 24.0

Überprüfe bitte mal Dein restliches
Programm sukzessive. Dann klappt auch das,
was Du möchtest :wink:

In der Tat! Du hast genau den Punkt getroffen, lieber Semjon! Ich bin
total begeistert, denn jetzt funktioniert mein C-Programm, wie es
soll. Ich mußte noch ein bißchen Arbeit reinstecken, aber gar nicht
mehr so viel. Jetzt klappt alles, wie es soll. Im Folgenden das
fertige C-Programm, für alle Elektrotechniker und alle, die es sonst
noch interessiert.

Liebe Grüße!

Bernhard

/\*\* Dieses Programm rechnet zwei Widerstandswerte aus, die in Serie 
verschaltet
dem gesuchten Widerstandswert am ehesten entsprechen. \*/

#include 
#include 

#define E\_REIHE 24.0


// Folgende Funktion berechnet den i-ten Widerstand der E-Reihe. 
double
Widerstand(int i)
{ 
 double power = (double)i/E\_REIHE; // Legt die 
Potenz fest, mit der die E\_Reihe berechnet wird
 double TheoretischerWiderstandswert = pow(10,power); // Berechnet 
10^(i/E\_Reihe), z.B. 10^(i/24)
 int ErstenBeidenZiffern = (int)(rint(TheoretischerWiderstandswert / 
pow(10,floor(power)-1))); // Berechnet die ersten beiden Ziffern des 
Widerstandswertes

 // Folgende Anweisung ist nötig, weil die Widerstandsreihe 
scheinbar nicht strikt nach Berechnung ausgewählt wurde
 // Hier wird also gegebenenfalls auf- bzw. abgerundet
 switch (ErstenBeidenZiffern)
 {
 case 26 : ErstenBeidenZiffern = 27; break;
 case 29 : ErstenBeidenZiffern = 30; break;
 case 32 : ErstenBeidenZiffern = 33; break;
 case 35 : ErstenBeidenZiffern = 36; break;
 case 38 : ErstenBeidenZiffern = 39; break;
 case 42 : ErstenBeidenZiffern = 43; break;
 case 46 : ErstenBeidenZiffern = 47; break;
 case 83 : ErstenBeidenZiffern = 82; break;
 } 
 return pow(10,floor(power)-1) \* (double)(ErstenBeidenZiffern); // 
Berechnet den realen Widerstandswertes des i-ten Widerstands
}



int
main()
{
 // Variablendeklaration
 unsigned int i, j;
 long int GesuchterWert, Gesamtwiderstand, BesterWert = 600000;
 long int ErsterWiderstand, ZweiterWiderstand;


 // Abfrage, welcher Wert gesucht ist:
 printf ("Welcher Widerstandswert ist gesucht? ");
 scanf ("%d", &GesuchterWert);


 // Berechnung der beiden besten Widerstände
 for (i=0; i 

Hallo nochmal.

In der Tat! Du hast genau den Punkt getroffen, lieber Semjon!
Ich bin
total begeistert, denn jetzt funktioniert mein C-Programm, wie
es
soll. Ich mußte noch ein bißchen Arbeit reinstecken, aber gar
nicht
mehr so viel. Jetzt klappt alles, wie es soll. Im Folgenden
das
fertige C-Programm, für alle Elektrotechniker und alle, die es
sonst
noch interessiert.

Jaja, so ein Exemplar schreibt gerade diesen Beitrag. ABER: der direkte und naive Kompilierversuch (copy’n’paste) unter der gestern angegebenen Basis führt zu folgendem Resultat: http://mitglied.lycos.de/schachspielen/www_ws2.PNG
Erste Fehlermeldung: „‚Potenz‘ : nichtdeklarierter Bezeichner“ :open_mouth:
Insgesamt 47 Fehler… Oder war das die Rache des Compilers ?

mfg M.L.

Hallo Markus,

Das Problem liegt sicherlich daran, daß wer-weiss-was die
Zeilenumbrüche versaut hat. Einige Zeilen, die zu lang waren, wurden
umgebrochen. Diesen Umbruch mußt Du wieder rückgängig machen, dann
klappt es bestimmt!

Grüße,

Bernhard

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]

Hallo zum 3.Mal

Das Problem liegt sicherlich daran, daß wer-weiss-was die
Zeilenumbrüche versaut hat. Einige Zeilen, die zu lang waren,
wurden
umgebrochen. Diesen Umbruch mußt Du wieder rückgängig machen,
dann
klappt es bestimmt!

Könnte stimmen. Wenn nicht gerade ein Rin’t’vieh (*g*) den Code so naiv übernimmt. Apropos rint: das ‚rint‘ scheint er wohl nicht zu verkraften. Siehe http://mitglied.lycos.de/schachspielen/www_rintvieh.PNG
Da muss doch bestimmt was anderes rein, oder ?

[Update]‚rint‘ wurde aus dem Code entfernt und ein weiterer Zeilenumbruch beseitigt. Jetzt geht’s :smile: Test mit 45 ergibt 45 als Ergebnis.

mfg M.L.

Hallo M.L.

http://mitglied.lycos.de/schachspielen/www_ws2.PNG
Erste Fehlermeldung: „‚Potenz‘ : nichtdeklarierter Bezeichner“

-O

Insgesamt 47 Fehler… Oder war das die Rache des Compilers

Hehe!

Aber hier mal das kompilierende Programm (meine Vorstellung davon).
Ob es „sachlich“ richtig läuft, kann ich aufgrund meiner
beschränkten Kenntnisse von E-Technik nicht überblicken.

Allerdings verwendet es eine Rundungsfunktion rint(), die
nicht überall dabei ist (hab ich mal angefügt - ohne Gewähr :wink:

/\* \* 
 Dieses Programm rechnet zwei Widerstandswerte aus, die in Serie 
 verschaltet dem gesuchten Widerstandswert am ehesten entsprechen. 
\* \*/

#include 
#include 

#define E\_REIHE 24.0

/\* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \*/

 double rint(double x)
{
 if( x \> 0 ) {
 int xint = (int) (x+0.5);
 if( xint % 2 ) {
 double diff = x - (double)xint;
 if( diff == -0.5 )
 return (double)(xint-1);
 }
 return (double)xint;
 } 
 else {
 int xint = (int) (x-0.5);
 if( xint % 2 ) {
 double diff = x - (double)xint;
 if( diff == 0.5 )
 return (double)(xint+1);
 }
 return (double)xint;
 }
} 
/\* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \*/

 int sauberer\_widerstand(double theoretischer\_widerstand, double power)
{
 int ErstenBeidenZiffern = (int)rint(theoretischer\_widerstand / pow(10, floor(power)-1)); 
 /\* Folgende Anweisung ist nötig, weil die Widerstandsreihe scheinbar nicht \*/
 /\* strikt nach Berechnung ausgewählt wurde - Hier wird also gegebenenfalls \*/
 /\* auf- bzw. abgerundet \*/
 switch (ErstenBeidenZiffern) {
 case 26 : ErstenBeidenZiffern = 27; break;
 case 29 : ErstenBeidenZiffern = 30; break;
 case 32 : ErstenBeidenZiffern = 33; break;
 case 35 : ErstenBeidenZiffern = 36; break;
 case 38 : ErstenBeidenZiffern = 39; break;
 case 42 : ErstenBeidenZiffern = 43; break;
 case 46 : ErstenBeidenZiffern = 47; break;
 case 83 : ErstenBeidenZiffern = 82; break;
 } 
 return ErstenBeidenZiffern;
}
/\* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \*/

 /\* Folgende Funktion berechnet den i-ten Widerstand der E-Reihe. \*/
 double Widerstand(int i)
{ 
 /\* Legt die Potenz fest, mit der die E\_Reihe berechnet wird \*/
 double power = (double)i / E\_REIHE; 
 /\* Berechnet 10^(i/E\_Reihe), z.B. 10^(i/24) \*/
 double theoretischer\_widerstand = pow(10, power); 
 /\* Berechnet die ersten beiden Ziffern des Widerstandswertes \*/
 int ziffern12 = sauberer\_widerstand(theoretischer\_widerstand, power);
 /\* Berechnet den realen Widerstandswertes des i-ten Widerstands \*/
 return pow(10,floor(power)-1) \* ziffern12; 
}
/\* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \*/
 int main()
{
 /\* Variablendeklaration \*/
 unsigned int i, j;
 long int GesuchterWert, Gesamtwiderstand, BesterWert = 600000;
 long int ErsterWiderstand, ZweiterWiderstand;

 /\* Abfrage, welcher Wert gesucht ist: \*/
 printf ("Welcher Widerstandswert ist gesucht? ");
 scanf ("%d", &GesuchterWert);

 /\* Berechnung der beiden besten Widerstände \*/
 for (i=0; iGrüße

CMБ

Und auch nochmals Hallo :wink:

Könnte stimmen. Wenn nicht gerade ein Rin’t’vieh (*g*) den
Code so naiv übernimmt. Apropos rint: das ‚rint‘ scheint er
wohl nicht zu verkraften. Siehe
http://mitglied.lycos.de/schachspielen/www_rintvieh.PNG
Da muss doch bestimmt was anderes rein, oder ?

Rint ist eine Funktion zum Runden des Wertes. Ich habe aber auch
gelesen, daß scheinbar nicht jeder Kompiler diese Funktion Rint
kennt. In diesem Falle

rint(zahl)

ersetzen durch

floor(zahl+0.5)

[Update]‚rint‘ wurde aus dem Code entfernt und ein weiterer
Zeilenumbruch beseitigt. Jetzt geht’s :smile: Test mit 45 ergibt
45 als Ergebnis.

Bei mir sieht das dann so aus:

Der beste gefundene Wert liegt bei 45 Ohm.
Das bedeuted eine Abweichung von insgesamt 0 Ohm bzw. 0.000 Prozent.
Dieser Wert wird erreicht bei einer Serienschaltung aus 2 Ohm und 43 
Ohm

Grüße!

Bernhard

etwas o.t.
Hallo Fragewurm,

double
Widerstand(int i)
{

Dieses Format solltest du dir abgewöhnen, also den Rückgabewert und den Funktionsnamen auf zwei Zeilen zu verteilen.

Besonders wenn man in fremdem, nicht dokumentierten, Code rumstochern muss, ist GREP eine wichtige Hilfe.
Allerdings zeigt einem GREP nur gerade diejenige Zeile an, auf welcher das gesuchte Wort gefunden wurde.
In deinem Fall also:

Widerstand(int i)

wesentlich hilfreicher wäre aber:

double Widerstand(int i)

Wenn’s dann so um 20’000 Zeilen geht, macht es einen grossen Unterschied.

MfG Peter(TOO)

Hallo Peter,

Hallo Fragewurm,

double
Widerstand(int i)
{

Dieses Format solltest du dir abgewöhnen, also den
Rückgabewert und den Funktionsnamen auf zwei Zeilen zu
verteilen.

Besonders wenn man in fremdem, nicht dokumentierten, Code
rumstochern muss, ist GREP eine wichtige Hilfe.
Allerdings zeigt einem GREP nur gerade diejenige Zeile an, auf
welcher das gesuchte Wort gefunden wurde.
In deinem Fall also:

Widerstand(int i)

wesentlich hilfreicher wäre aber:

double Widerstand(int i)

Wenn’s dann so um 20’000 Zeilen geht, macht es einen grossen
Unterschied.

Deinen Denkanstoß nehme ich dankbar an. Ich bin auch der Meinung, daß
in einem nicht ausreichend dokumentiertem Code Deine vorgeschlagene
Schreibweise sinnvoll ist.

Die Frage ist nur: Sollte ich mir meine Schreibweise deswegen
abgewöhnen? Viel Unterschied macht es ja schließlich nicht. Ich finde
meine Schreibweise zwar etwas übersichtlicher, aber das ist
vielleicht auch Geschackssache.

Nur, ich sag’s mal so: Ich habe nicht vor, unzureichend
dokumentierten Code 20.000 Zeilen weit zu strecken. Für solche Fälle
gibt es Doxygen, eine Dokumentationsmöglichkeit, die mich schwer
begeistert hat. Doxygen erstellt aus den Kommentaren im Quellcode
automatisch eine wunderbare Doku, mit Erklärung zu den einzelnen
Variablen und und und.

Von da her werde ich wohl bei meiner Schreibweise bleiben.

Grüße!

Bernhard

P.S.: Btw., ich glaube, mit perl kann man sogar nach einem Match über
mehrere Zeilen parsen. Fragt mich aber bitte nicht, wie!
P.S.S.: Der frühe Fragewurm fängt den Vogel!