» »

[c] osnove

[c] osnove

slovencl ::

Imam enostaven programček:
float x=4.1;
	
if(x==4.1) { printf("da"); }
else { printf("ne"); }


Rezultat je (zanimivo) ne. Zdej mi pa ni jasno zakaj je tako. Vzrok naj bi bil v tem, ker so konstante v c ju definirane kot double, ampak vseeno ne vem zakaj tak rezultat.

Tole npr da rezultat ne:
float x=4.1;
double y=4.1;
	
if(x==y) { printf("da"); }
else { printf("ne"); }


Tole pa da rezultat da:
char x=4;
int y=4;
	
if(x==y) { printf("da"); }
else { printf("ne"); }


Zadeva zgleda zelo podobna, rezultat pa ne. V čem je štos?
  • spremenil: slovencl ()

Steinkauz ::

Glih kar prebral iz prosojnic :
Včasih da program napačne numerične odgovore.
Do tega lahko pride zaradi napake zaokroževanja (rounding error), ki izhaja iz omejene natančnosti računalnika.
double x = 0.1;
while ( x != 0.2) {
x += 0.01;
System.out.println(x);
}
Ta program bi krožil neprekinjeno. Spremenljivka x nikar ne doseže vrednosti točno 0.2 (x zgreši vrednost 0.2 za približno 8.3 X 10-17).
Bolje je, če stavek while zamenjamo z:
while ( x <= 0.2) {

MasterMind ::

Celoštevilski znaki so lahko samo 1, 2, 3 itd. Medtem ko realnih števil med 4.1 in 4.2 je pa neskončno. Zato že tko ali tako se pri realnih številih ne uporablja enačaja.

Razlog za to stvar, pa nebi znal povedati. (mogoče je razlog v številu alociranega prostora ? )

edit: Steinkauz je bolj logičn razlog napisal :)
Gentoo, KDE uporabnik.

Zgodovina sprememb…

slovencl ::

Se pravi bi lahko za neko število veljalo, da bi bil rezultat zaokroževanja kljub temu ustrezen, in bi bil rezultat if stavka v mojem zgornjem primeru lahko tudi da?

Kako pa bi iz teh dveh (float in doble) spremenljivk dobil dejansko vrednost (lahko tudi v binarnem) katero ima vpisano?

slovencl ::

Sem poskusil tole:
float x=4;
double y=4;
	
if(x==y) { printf("da"); }
else { printf("ne"); }


rezultat je da...

MasterMind ::

Ker si enačil dve celi števili med seboj (kljub temu, da sta realnih tipov). Tukaj ni nobenih problemov.
Gentoo, KDE uporabnik.

Mavrik ::

Razlog za to stvar, pa nebi znal povedati. (mogoče je razlog v številu alociranega prostora ? )


Razlog je v prezentaciji decimalnih števil v računalniškem pomnilniku. Beri.
The truth is rarely pure and never simple.

slovencl ::

Ne vem zakaj bi bil razlog število decimalnih mest v pomnilniku?



Sem pa poskusil tole:
double z=282.480347;
	float x=(float)z;
 	double y=z;
 	int i=0;
 	
 	if(x==y) printf(&quot;|da|&quot;);
 	else printf(&quot;|ne|&quot;);
 	
 	while(1)
 	{
		
		if(x==y) { printf(&quot;  %f&quot;,x); break; }
 		x=(float)z;
 		y=z;
		z=z+0.0000001;
 	}
	printf("konec %f  %f  %f",x,y,x-y); 


rezultat je:
|ne| 331.971924konec 331.971924 331.971924 0.000000

ampak če potem dobljeno število ponovno vnesem na začetku v spremenljivko double z, vedno dobim ob prvem preverjanju odgovor |ne|. Zakaj pa to, saj sem mu vnesel nekaj, kar je že sam preveril, da je enako, potem pa ugotovi, da ni enako. Nč jasn...

Zgodovina sprememb…

  • spremenil: slovencl ()

Pimoz ::

heh...pretvorba iz 4.1 v float ni auto vsaj kokr sm jst pogruntu. se pravi rešitev je:
#include <stdlib.h>
#include <iostream>

using namespace std;

int main () {
    float x = 4.1;
    
    if (x == (float) 4.1)
        cout << "yes" << endl;
    else
        cout << "no" << endl;
    
    system ("PAUSE");
    return 1;
}

slovencl ::

Primoz, to je rešitev, samo ne na moje vprašanje...

Pimoz ::


double z=282.480347;
	float x=(float)z;
 	double y=z;
 	int i=0;
 	
 	if(x==y) printf(&quot;|da|&quot;);
 	else printf(&quot;|ne|&quot;);


um x je tipa float y pa tipa double...v if napiši if (x == (float) y) pa bo delalo

sherman ::

Zakaj pa to, saj sem mu vnesel nekaj, kar je že sam preveril, da je enako, potem pa ugotovi, da ni enako. Nč jasn...

Hehe, zdej pa poskusi z nastavit še na npr. 331.97198486328125 in se čudi.
Če ti to še ni dovolj nastavi z na 331.971984, ki ima manj decimalnih mest in bi, če deluje s prejšnjo cifro, moralo delovati tudi s to, a ne? >:D

No, razlog da 331.971924::Double != 331.971924::Float je v tem, da 331.971924 nima končnega zapisa v dvojiškem številskem sestavu (tako kot 1/3 nima v desetiškem) in zato je približek pač malo drugačen pri double kot pri float.

Zgodovina sprememb…

  • spremenilo: sherman ()

celebro ::

In zato v takih primerih uporablja

if (abs(x-y)< 0.000001)
printf("da");
else printf("ne");


Kjer uporabiš poljubno natančnost.

fiction ::

Glede stevil v zapisu s plavajoco vejico je jasno. Doloceno destisko stevilo ima v dvojiskem sistemu lahko neskoncno decimalk. Ce primerjas taki dve stevili je tisto v double avtomaticno bolj natancno (in drugacno) od tistega v float spremenljivki, medtem ko je recimo 4 double enak 4 floatu. Typecast naj bi vse skupaj resil, bolj elegantno pa je seveda, ce gledas da je razlika manjsa od nekega epsilona, tako kot je napisal celebro.

Se en malo bolj zloben primer (ki pa nima veze z IEEE 754):
char ch = 0xff;
if (ch == 0xff) 
  printf("da");
else
  printf("ne");

No, odkrijte zakaj tole izpise vedno ne.
Hint: predznacena / nepredznacena stevila ter "sign extension".

KaRkY ::

To pa je odgovor ne ker je char stevilo lahko največ 255 0xFF pa je 256 in ga potem računalnik da na 1 če se prav spomni pri primerjavi pa ga primerja z int ta pa je lahko 256. Mislim da je zato nisn pa 100%.

celebro ::

0xFF je 255

Jean-Paul ::

gcc javi tole:
warning: comparison is always false due to limited range of data type

Mavrik ::

Mah, sicer ne poznam for C kompajlerja, sam gotovo zadeva konverta unsigned 8-bitni int (torej char) v signed 32-bitni int pred primerjanjem (0xFF razume kot 32-bitni signed int). Problem nastane, ker zadevo casta na "signed" način, torej z razširanjem predznaka in potem posledično dela primerjavo 0xFFFFFFFF == 0xFF.
The truth is rarely pure and never simple.

fiction ::

Mavrik ma prav. Razen tega, da je char po defaultu tudi signed, ce bi bil unsigned tole ne bi delovalo.

Char je ponavadi velik 8 bitov, int pa 32 (odvisno od arhitekture).
V ch zapises 0xff. Ko to primerjas z 0xff je to v bistvu primerjava 8 bitnega
predznacenega stevila (ch) z 32 bitnim predznacenim stevilom 0xff
(stevilcna konstanta brez . je po defaultu int).
Zato se tisti char razsiri v vecji int (ampak ker je vse skupaj predznaceno stevilo,
se naredi razsiritev predznaka in se tista vodilna 1 skopira v vse sprednje bite).
Tako dobis iz ch integer 0xffffffff in to primerjas s konstanto 0x000000ff kar pa logicno
ni enako.

Mavrik ::

Razen tega, da je char po defaultu tudi signed, ce bi bil unsigned tole ne bi delovalo.


Ah, to torej razloži celo stvar. V Cju že en čas nisem nič delal, bil sem pa z neznanega razloga prepričan da je char unsigned... oh well.
The truth is rarely pure and never simple.

mojcica54 ::

Oj! Tud js mam en "hudicevo lahek" problem, ki pa nevem zakaj ne dela. imam tole proceduro:

void vnos_imen(struct novi U){

dat1=fopen("imena.dat", "w");//odpremo datoteko in dadajamo na konec//
printf("Vpisi ime: ");
gets(U.ime);
fwrite(&U, sizeof(U), 1, dat1);
fclose(dat1);//zapremo datoteko
}

ta gets mi noce delat. kr ven mi mece iz procedure sploh noce nic prebrat oziroma sploh ne morm nic napisat. Prosim, za pomoc ker bom res ostala ze brez las tolk sm si jih ze spipala :D
Hvala!!!!!!

Pimoz ::

kje imaš definiran dat1, napisat morš parametr wb namest w ker delaš z binarno datoteko

fiction ::

dat1 je najbrz nekje definiran kot FILE *dat1.
Manjka preverjanje tega, ce je odpiranje datoteke uspelo. Nek dodaten if, bi ti lahko zelo olajsal odkrivanje problema. Potem namesto "w" uporabi "a", ker "w" prepise vsebino in ne dodaja na konec (tako kot pravi komentar).

Zanimivo bi bilo videti kako izgleda ta struct novi. Saj se zavedas tega, da tukaj v bistvu dobis kot parameter nek obstojeco strukturo tipa novi, ji spremenis ime in jo zapises v datoteko, ne? Vnos_imen je kar se tega tice malo zavajujoce ime funkcije.

Nikoli, ampak res nikoli ne uporabljat gets(), ker to prebere toliko znakov kolikor jih uporabnik vpise in torej povzroci prekoracitev izravnalnika (buffer overflow), kar pa je zelo huda varnostna ranljivost!
Jasno tukaj lahko kdo rece, da vse skupaj nima smisla - itak ne gre za neko resno aplikacijo, ampak v vsakem primeru se je lepo nauciti dobre prakse in uporabiti fgets() ze sedaj.

mojcica54 ::

dat1 mam definirano v glavnem programu. Tudi na w deluje.

mojcica54 ::

aha, hvala. in kako potem deluje fgets(). Aja malo sem skrajsala podprogram, drugace imam se vec vnasanj, tak, da je smiselno uporabit stukture (ime, priimek, aktivnost, razred, naslov) in te strukture pol zapisem v datoteko, da kasneje lahko se uporabit datoteke.
Hvala za nasvet v zvezi z gets(). :D

Pimoz ::

dat1 mora bit globaln ne v mainu....
pa res ifej odpiranje datoteke pa zapisvanje vanjo... ponavad so lih preverjanja pa exceptioni trn v peti programerjem

mojcica54 ::

no zdej sm malo premislala, fgets() je za branje iz datoteke js pa morm brat iz konzole :D

Senitel ::

Kako sploh izgleda ta "struct novi"?

mojcica54 ::

struct novi{
char ime[20];
char priimek[20];
char razred[20];
char paralelka[4];
char aktivnost[20];
}U;

celebro ::

fgets(str, 20, stdin); bere iz konzole

fiction ::

fgets() bere iz kateregakoli streama. Namesto

gets(U.ime)

tako lahko reces nekaj ala

fgets(U.ime, sizeof(U.ime), stdin);
Edina razlika je v tem, da bo fgets() pustil notri znak za novo vrstico na koncu, ki pa ga lahko odstranis z
char *p = index(U.ime, '\n');
if (p != NULL)
{
  *p = '\0';
}

BigWhale ::

fiction, that is _the least_ of her problems... ;>

Bi pa precej pomagalo, ce bi nam gospodicna blagovoljila malo bolj podrobno opisati kaj dejansko ne dela. :) Oz kaj pomeni 'metanje ven iz procedure' :)

Gre za runtime error? syntax error? :)

mojcica54 ::

fantje, ne boste vrjeli. Po celodnevnem programiranju mi je zdej to zacel cudezno delat, pa ne me vprasat kaj sm nardila da dela, ampak dela :D Hvala za vso pomoc!Pa vas bom se jutri kej naprosla za pomoc :D Hvala!

Pimoz ::

pismu...pa spet nismo nc zvedl :D
k je folk tok skrivnostn :P

mojcica54 ::

no pa da boste vsi zvedli :D
to je moja preljuba procedura:D
struct sportni_dan {
        char naziv_sportnega_dne[20];	
        char naziv_sole[20];
        char kraj_izvajanja[15];
        char dan[4]; // datum izvajanja
        char mesec[4];
        char leto[6];
        char ura[4]; // ura zacetka  
}SP;
datoteke pa so globalne

void spreminjanje_naziv(struct sportni_dan Sp){
char iskani1[15];
char novi1[15];
FILE *tmp;    
     printf(&quot;Vnesi naziv sportnega dne: &quot;);
     gets(iskani1);
     printf(&quot;Vnesi novo naziv sportnega dne: &quot;);
     gets(novi1);
     
      dat3=fopen(&quot;sportni_dan.dat&quot;, &quot;r&quot;);//odprem datoteko za branje - kazalec je na zacetku
      tmp=fopen(&quot;pomozna.dat&quot;, &quot;w&quot;);
       while (!feof(dat3)){
          if (fread(&SP, sizeof(SP), 1, dat3)==0)
               break;
          if (strcmp(iskani1, SP.naziv_sportnega_dne)!=0)
             fwrite(&SP, sizeof(SP), 1, tmp);
          if (strcmp(iskani1, SP.naziv_sportnega_dne)==0){
             strcpy(SP.naziv_sportnega_dne, novi1);
             fwrite(&SP, sizeof(SP), 1, tmp);
             }                           
       }
       fclose(tmp);
       fclose(dat3);
       
      dat3=fopen(&quot;sportni_dan.dat&quot;, &quot;w&quot;);
      tmp=fopen(&quot;pomozna.dat&quot;, &quot;r&quot;);
       while (!feof(tmp)){
          if (fread(&SP, sizeof(SP), 1, tmp)==0)
               break;
          fwrite(&SP, sizeof(SP), 1, dat3);                             
       }
       fclose(tmp);
       fclose(dat3);  
}

no problem je spet ta gets, vem da tezim, sam sej veste, da je pomembno da nardim ok (faks) :D

Hvala!!!!!!!

Zgodovina sprememb…

  • spremenil: Senitel ()

fiction ::

Ce citiram iljev blog: "The 90's called, they want their bugs back :-p"

if (strcmp(iskani1, SP.naziv_sportnega_dne)!=0)
if (strcmp(iskani1, SP.naziv_sportnega_dne)==0)

Khm, za take primere obstaja "else" in tisto kar naredis v obeh primerih daj pac ven ne pa da nekaj izvedes, ce je pogoj izpolnjen in tudi ce ni.

V tvojem sportnem dnevu je presenetljivo veliko nizov znakov.

Ok spreminjanje_naziv() ocitno prepise vse zapise iz sportni_dan.dat v pomozna.dat pri cemer spremeni v vseh zapisih, ki ustrezajo naziv.
Ne vem pa zakaj funkciji sploh podas kot parameter struct sportni_dan Sp. Tisto kopiranje iz pomozna.dat v sportni_dan.dat na koncu je dokaj brezveze. Naredi samo rename() ali kaj takega.

Kaj tocno se ne dela?
Aja BTW: za ker faks pa mas to?


Vredno ogleda ...

TemaSporočilaOglediZadnje sporočilo
TemaSporočilaOglediZadnje sporočilo
»

Prikaz programa v windowsih

Oddelek: Programiranje
101253 (1171) s51as
»

programiranje C

Oddelek: Programiranje
62423 (2285) bozjak
»

[C] bitni operator (strani: 1 2 3 )

Oddelek: Programiranje
1125513 (4346) Thomas
»

[C++][Naloga_polja]MIN in MAX polja, izpis za x.100 stevil

Oddelek: Programiranje
222934 (2745) snow
»

[c] char zadeva

Oddelek: Programiranje
222245 (2043) TheCyborg

Več podobnih tem