Program C#
ozone: Podpowie mi ktoś gdzie mam błąd?
Zadanie:
Należy wczytać ciąg liczb rzeczywistych. Wczytywanie należy zakończyć gdy pojawi się
liczba 0. Obliczyć sumę wczytanych liczb.
Program:
#include <stdio.h>
int main()
{
float n;
float k=0;
do{
printf("n= ");
scanf("%f",n);
k=k+n;
}
while(n!=0);{
printf("wynik:%f", k);
}
getch();
return 0;
}
4 kwi 12:56
Patronus: nie znam dobrze języka, ale algorytm wydaję się ok − a co ci dokładnie nie działa? Źle wczytuje
czy jest błąd przy kompilacji?
4 kwi 13:05
xcv: no właśnie problem w tym, że wczytuje mi n i gdy za n dam 0 to kończy mi program i nie
wyświetla wyniku jakby w ogóle pomijał printf("wynik:%f", k);
4 kwi 13:08
ozone: Napisałem to jeszcze w ten sposób:
#include <stdio.h>
int main()
{
float n;
float k=0;
do{
k=k+n;
printf("n= ");
scanf("%f",&n);
if(n==0){
printf("wynik %f", &k);
}
}
while(n > 0);
return 0;
}
Tym razem wyswietla mi np:
n=2.2
n=1
n=3
n=0
wynik 0.00000
O co w tym chodzi?
4 kwi 14:30
ozone: *k=k+n; powinno być 2 linie niżej
4 kwi 14:33
Trivial:
Masz & w printfie oraz to o czym mówiłeś: k = k+n jest za wysoko.
Program działa, choć porównywanie floatów w stylu x == 0 jest bardzo niebezpieczne.
http://ideone.com/TeFEUM
4 kwi 16:26
ozone: Wyświetla cały czas wynik 0.000 obojętnie jakie n podam w takim razie to wina kompilatora?
No i w jaki inny sposób zapisać to o czym mówisz x == 0 ?
4 kwi 17:26
ozone: Ok już wszystko działa dzięki wielkie ale nadal interesuje mnie dlaczego porównywanie w ten
sposób może szkodzić
4 kwi 17:37
Trivial:
Takie porównywanie to zła praktyka dlatego, że liczby zmiennoprzecinkowe mają jeden bardzo
poważny problem − są niedokładne (wynik jest zaokrąglany/obcinany). Dochodzi jeszcze
rozróżnienie między float (0.1f) a double (0.1). Oto przykład:
http://ideone.com/rH1dxn
4 kwi 18:45
Trivial:
Prymitywnym rozwiązaniem tego problemu to warunek |x − x*| < ε, np.:
double eps = 0.000001;
if (fabs(x − 0.1) < eps) { ok; }
4 kwi 18:50
ozone: Hmm dopiero zaczynam przygodę z programowaniem ale mniej więcej wiem o co Ci chodzi.
Przeanalizuję sobie ten przykład jeszcze jak poznam więcej podstaw. zabrałem się za to dopiero
od wczoraj

No i dzięki za pomoc.
4 kwi 20:01
Trivial: Nie musisz wiedzieć jak działa program, który to testuje. Interesują Cię tylko wyniki.
4 kwi 20:07
ozone: W takim razie chodziło tam o to, że jak wykonujemy operacje na zmiennych float i double to
wychodzą różne wyniki?
4 kwi 20:09
ozone: %−25s − to oznacza że zczytuje jakąś część wartości argumentu funkcji test?
4 kwi 20:18
Trivial:
Jak mówiłem, nie musisz wiedzieć jak działa makro TEST. Ono po prostu wypisuje OK jeśli równość
zachodzi i FAIL jeśli nie zachodzi. %−25s to specyfikator formatu funkcji printf (taki jak %f,
ale rozbudowany):
% → znacznik
− → wyrównaj do lewej
25 → wypisany ciąg powinien mieć długość co najmniej 25 znaków
s → typ zmiennej to łańcuch znakowy.
#x → argument w postaci łańcucha znakowego (kod)
(x) → wartość warunku
(x) ? "OK" : "FAIL" → jeśli (x) to "OK", w przeciwnym razie "FAIL".
Mało istotne! Ważne są wyniki działania tego programiku.

Np. to, że 1.1 − 0.1 == 1.0 jest
OK, ale już 0.11 − 0.1 == 0.01 nie jest. Dzieje się tak dlatego, że liczby zmiennoprzecinkowe
są przechowywane w postaci binarnej. W zapisie dwójkowym 0.1 jest tak naprawdę ułamkiem
okresowym.
0.1 (dec) = 0.000110011001100110011001100110011.... (bin)
Oraz:
0.11 (dec) = 0.000111000010100011110101110000101.... (bin)
Przechowywana jest skończona wartość tej postaci (ucinamy na pewnym bicie). Przy wykonywaniu
odejmowania 0.11 − 0.1 błędy zaokrągleń nie dają dokładnego wyniku 0.01 i warunek 1.1 − 0.1 ==
1.0 nie zachodzi.
4 kwi 20:38
Trivial:
Miało być
0.11 − 0.1 == 0.01 nie zachodzi. 1.1 − 0.1 == 1.0 zachodzi − widocznie tutaj te
błędy się jakoś skracają.

Dlatego nie powinno się sprawdzać równości liczb
zmiennoprzecinkowych − trzeba być ekspertem obliczeń numerycznych, żeby wiedzieć co to
porównanie dokładnie oznacza.
4 kwi 20:44
ozone: Swietnie wytlumaczone!

gdyby tak to tlumaczyli na wykladach ...
4 kwi 21:57