PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Zahls C-Kniffelclub Runde 1


Zahl
05.11.07, 14:07:08
So, hier gib es ja wahrscheinlich sehr viele C Programmierer *hust*, darum hier
mal ein lustiges Rätsel. Heute Morgen meldete sich ein Kollege bei mir mit
einem simplen C Programm, was offensichtlich falsch rechnet.
#include <stdio.h>
//#include <math.h>

int main() {
int iBas = 0, iPo = 0;
int erg;
do {
iPo=1;
iBas = iBas + 1;
printf("\n%d: ", iBas);
do {
erg = pow(iBas,iPo);
printf(" %d (%d^%d)", erg,iBas,iPo);
//printf(" %d ",erg);
iPo = iPo + 1;
} while( iPo != 4 );
} while( iBas != 7 );

erg=pow(5,2);
//printf("\n\n%d ", iPo);
printf("\n\n%d ", erg);

return 0;
}

Die Lösung ist recht einfach, aber im ersten Moment guckt man mal doof. Wer
nicht so fit in Mathe ist und den Fehler nicht sofort findet: Die 5er Reihe ist falsch.
(Evtl. tritt das Problem auch nicht mit allen Compilern auf, in dem Fall war es gcc)


Viel Spaß. Wer das Problem löst kriegt nen neuen Usertitel :-D

blue
05.11.07, 14:21:26
Das liegt an den Castings. pow ist mehrfach überladen. Es gibt aber keine pow Funktion, die zwei Integer übernimmt. Aus dem Grund immer geeignet casten.

Aber hier sieht man mal wie stark der Visual C++ Compiler ist (Joa, ich liebe die M$ IDE :fin:), der hat mich deinen Code erst gar nicht kompilieren lassen ;)

#include <stdio.h>
#include <math.h>

int main() {
int iBas = 0, iPo = 0;
int erg;
do {
iPo=1;
iBas = iBas + 1;
printf("\n%d: ", iBas);
do {
erg = (int)pow((double)iBas,(double)iPo);
printf(" %d (%d^%d)", erg,iBas,iPo);
//printf(" %d ",erg);
iPo = iPo + 1;
}while( iPo != 4 );

} while( iBas != 7 );

erg=(int)pow((double)5,(double)2);
//printf("\n\n%d ", iPo);
printf("\n\n%d ", erg);

return 0;
}


Ach und jetzt verpass mir mal nen neuen Benutzertitel :fin:

Zahl
05.11.07, 14:41:54
Minus 10 Punkte für Blue. Das ist C und MSVC++ ist kein richtiger C Compiler :fin:
Unter gcc löst das ganze das Problem übrigens nicht. ;)

EDIT: So sieht die Ausgabe vom obigen Programm mit gcc aus:
1: [ 1 ( 1 ^ 1 )][ 1 ( 1 ^ 2 )][ 1 ( 1 ^ 3 )]
2: [ 2 ( 2 ^ 1 )][ 4 ( 2 ^ 2 )][ 8 ( 2 ^ 3 )]
3: [ 3 ( 3 ^ 1 )][ 9 ( 3 ^ 2 )][ 27 ( 3 ^ 3 )]
4: [ 4 ( 4 ^ 1 )][ 16 ( 4 ^ 2 )][ 64 ( 4 ^ 3 )]
5: [ 5 ( 5 ^ 1 )][ 24 ( 5 ^ 2 )][ 124 ( 5 ^ 3 )]
6: [ 6 ( 6 ^ 1 )][ 36 ( 6 ^ 2 )][ 216 ( 6 ^ 3 )]

ultimo
05.11.07, 14:47:41
keine ahnung...kann nur Java und n bissle TurboPascal :D

blue
05.11.07, 14:49:32
keine ahnung...kann nur Java und n bissle TurboPascal :D

Sitz du im Matheunterricht auch da und sagst "Nee, a*b kann ich nicht rechnen, ich kann nur 1+1, 1+2 ..."?!? ~.~

<Zahl>aber ums kurz zu machen
<Zahl>es liegt schon an den datentypen
<Zahl>nur
<blue>hrough ..
* blue hatte recht :fin:


Und ich hatte doch Recht :fin:

SilberEisen
05.11.07, 16:40:36
Hm, ich hab so garkeine Ahnung von dem was ihr da schreibt aber 5^2 is nich 24 und 5^3 auch nich 124... :-/

raven
05.11.07, 23:18:29
LDP:


[...]mit einem simplen C Programm, was offensichtlich falsch rechnet.[...]


/me prepares SilberEisen to be shown on rotten.com :fin:

SilberEisen
06.11.07, 16:46:37
Hehe, gut ich geh mich vergraben :D :o

omg gut ich sollte vielleicht doch wenigstens versuchen mir so Sachen mal durchzulesen bevor ich antworte :p aber gut....

Lord_Pinhead
09.11.07, 03:02:21
Wie hast du es übersetzt?


gcc -lm -o zahl zahl1.c


bringt die richtigen Ergebnisse


1: 1 (1^1) 1 (1^2) 1 (1^3)
2: 2 (2^1) 4 (2^2) 8 (2^3)
3: 3 (3^1) 9 (3^2) 27 (3^3)
4: 4 (4^1) 16 (4^2) 64 (4^3)
5: 5 (5^1) 25 (5^2) 125 (5^3)
6: 6 (6^1) 36 (6^2) 216 (6^3)
7: 7 (7^1) 49 (7^2) 343 (7^3)


Blues Code ist irgendwie eigenartig das er aus aus dem pow, was im Prototyp ja ein double ist, ein int machen will, die Eingabewerte aber extra nochmal als double deklariert, strange
Egal ob ich in die cmath (für C++) oder math.h (für C) kucke, es sind immer double wert:

double pow(double x, double y) __THROW __attribute__((__const__));


Egal, warum gibt euer Compiler falsche werte aus?

blue
09.11.07, 03:10:30
Blues Code ist irgendwie eigenartig das er aus aus dem pow, was im Prototyp ja ein double ist, ein int machen will, die Eingabewerte aber extra nochmal als double deklariert, strange
Egal ob ich in die cmath (für C++) oder math.h (für C) kucke, es sind immer double wert:

double pow(double x, double y) __THROW __attribute__((__const__));


Egal, warum gibt euer Compiler falsche werte aus?

RichtÖÖÖÖöööög .. der Rückgabewert der pow Funktion ist vom Typ "double". Allerdings wird hier einem Integer (erg) das Ergebnis von pow zugewiesen. Ich caste also das Ergebnis in einen Integer um ohne Warnung des Compilers das Ergebnis zuzuweisen.
Nicht eigenartig sondern pingelig ;)

Zahl
09.11.07, 09:30:20
Scheint wohl an den verschiedenen gcc Versionen zu liegen. Ich habs ohne -lm gemacht,
Unter Win und Solaris kriegt man das oben angegebene falsche Ergebnis. Castet man das
Ergebnis von pow direkt in nen int gehts schief. Nimmt man erst n Double und castet den
dann noch in nen int haut es hin. Sehr schtreynsch.

Lord_Pinhead
10.11.07, 21:57:55
Ohne -lm weiß GCC bzw. der Linker ja nicht das er die math.c mit einlinken soll

aus der Manpage

-llibrary
-l library
Search the library named library when linking. (The second alternative with the library as a separate argument is
only for POSIX compliance and is not recommended.)

It makes a difference where in the command you write this option; the linker searches and processes libraries and
object files in the order they are specified. Thus, foo.o -lz bar.o searches library z after file foo.o but before
bar.o. If bar.o refers to functions in z, those functions may not be loaded.

The linker searches a standard list of directories for the library, which is actually a file named liblibrary.a. The
linker then uses this file as if it had been specified precisely by name.

The directories searched include several standard system directories plus any that you specify with -L.

Normally the files found this way are library files---archive files whose members are object files. The linker han-
dles an archive file by scanning through it for members which define symbols that have so far been referenced but not
defined. But if the file that is found is an ordinary object file, it is linked in the usual fashion. The only dif-
ference between using an -l option and specifying a file name is that -l surrounds library with lib and .a and
searches several directories.


Den Fehler den mir GCC ausgibt wenn man -lm weglässt kann man ja per Google suchen und findet auch die Antwort, normal denke ich ja das es sich mit einem include erledigt hat.

@Blue
Dann leg doch gleich von Anfang an fest das die 2 Variablen double sind und keine integer, deine Version ist etwas Spagettocode mässig

blue
11.11.07, 03:18:48
@Blue
Dann leg doch gleich von Anfang an fest das die 2 Variablen double sind und keine integer, deine Version ist etwas Spagettocode mässig

Ich habe mich einfach nur an Zahls Version orientiert. Wenn natürliche Zahlen erwartet werden, wozu dann fließkomma Werte verwenden?

Zumal mir das Problem mit der pow() Funktion schon des öfteren aufgefallen ist. Dadurch erkennt man aber, dass gewisse Castings einfach nötig sind um ein Programm richtig lauffähig zu machen.
Andersrum verstehe ich nicht, warum in der C Library sieben verschiedene pow Funktionen existieren, keine von denen aber Integer entgegen nehmen bzw. zurückgeben.

Lord_Pinhead
13.11.07, 17:30:56
Es gibt alternativen, ansonsten schreibt man sich eine alternative pow() Funktion oder nutzt Onkel Google, dort hab ich auf Anhieb 2 Stück gefunden.
pow() kommt auch mit normalen Integer Werte aus und soviel ist das nicht das es jetzt als schwer bezeichnet werden kann.


inline int pow(int x, int p)
{
if(p == 0) return 1;
if(x == 0 && p > 0) return 0;
if(p < 0) {assert(x == 1 || x == -1); return (-p % 2) ? x : 1;}

int r = 1;
for(;;) {
if(p & 1) r *= x;
if((p >>= 1) == 0) return r;
x *= x;
}
}


Der Code stammt von http://www.math.ualberta.ca/~bowman/pow.h und nicht auf meinen Mist gewachsen und ich hab ihn nicht !getestet!. Wegen einer einzigen Funktion muss man ja nicht gleich die komplette Headerfile einlinken, ist zwar nicht so schlimm wenn man dynamic linking verwendet, allerdings kann man nicht immer beim Zielsystem vorraussetzen das es die nötigen Librarys mitbringt.

p.s. die math.h hat sehr sehr sehr wenig Funtionen die man brauchen könnte die ein int entgegennehmen. Ist sowisso recht sinnlos, den die einfachen Funktionen die dort drin sind schreibt man sich doch schnell, oder brauch jemand sqrt() :) Da schreib ich doch gleich x*x, ist kürzer