Strona używa cookies (ciasteczek). Dowiedz się więcej o celu ich używania i zmianach ustawień. Korzystając ze strony wyrażasz zgodę na używanie cookies, zgodnie z aktualnymi ustawieniami przeglądarki.    X

Czy komputer potrafi liczyć?

Co będzie, gdy powiem Wam, że komputer nie zawsze zwraca poprawny wynik działań arytmetycznych? I wcale nie chodzi tutaj o skomplikowane obliczenia! Okazuje się, że nasz blaszany przyjaciel ma problemy nawet z trywialnymi operacjami arytmetycznymi.
Wszak każdy potrafi powiedzieć ile wynosi wynik takiego działania jak 1000.1 - 1000. Niewiele zmieni, jeśli zamiast 1000, sto razy odejmę 10 (bo 10*100 = 1000). Tylko czy oby na pewno? Sprawdźmy to na prościutkim programie: float x = 1000.1; int i; for(i=0;i<100;i++){ x = x-10; } std::cout<<x; Kompilujemy i... wynik jest niepoprawny

Sprawdzamy kod jeszcze raz - wszystko wydaje się ok.

Więc w czym problem?

Problemem okazuje się być sposób, w jaki zapisywane są liczby w naszych komputerach. To, oraz komplikacje które z tego wynikają. Nie mam zamiaru tutaj tego opisywać, bo nie widzę sensu w przepisywaniu wikipedii, gdzie jest to dość ładnie opisane. Zresztą większość osób czytających ten wpis zapewne ma o tym pojęcie, możliwe jednak że nie zdają sobie sprawy z tego, jak bardzo może to zakłamywać wyniki prostych operacji, jak ta wyżej. Przypomnę tylko w skrócie, że na skończonej liczbie bitów nie da się zapisać każdej liczby (tak jak na skończonej liczbie cyfr dziesiętnych nie da się zapisać każdej liczby, przykładowo 1/3). W systemie binarnym mamy problem nawet z taką liczbą jak 1/10 ! Przez to podczas wykonywania obliczeń otrzymujemy wyniki z błędem, zwłaszcza przy odejmowaniu bliskich sobie liczb (jeśli znajdzie się grono odbiorców mogę pokusić się o opisanie tego dokładniej - dzisiaj pokażę jedynie kilka ciekawych błędów). Przeważnie błędy te są na tyle małe, że ich nie zauważamy, ale jak widać przy stukrotnym powieleniu operacji błędy się kumulują dając już zauważalne odchylenie. Okazuje się, że może być o wiele gorzej. Albo dziwniej...

float x = 1.0; while(1!=x+1){ x = x/2; } if(x!=0){ std::cout<<"Komputer twierdzi ze x jest rozne od 0"<<std::endl; } if(x+1 == 1){ std::cout<<"Komputer twierdzi ze x+1 jest rowne 1, a jednoczesnie x = " << x<<std::endl; } if((x!=0) && (x+1 == 1)){ std::cout<<"x+1 = 1, ale x nie jest zerem?!"; }

Kolejność dodawania?

Było wielokrotne odejmowanie, pobawmy się zatem dodawaniem :) Pytanie brzmi: czy oby na pewno kolejność dodawania nie ma znaczenia? Zobaczmy to na przykładzie:float s1, s2; int i, j; s1 = 0.0; s2 = 0.0; for(i=1; i<=100000; i++){ s1 = s1 + 1.0/(float)(i*(i+1)); } for(j=100000; j>=1; j--){ s2 = s2 + 1.0/(float)(j*(j+1)); } std::cout<<s1<<std::endl<<s2;Niby nic złego się nie powinno stać, ale zerknijmy na wyniki:

I co w związku z tym?! Przecież to malutkie błędy!

Błędy są malutkie, bo przykłady nie należą do zbyt wyrafinowanych. Nie oznacza to, że błędy numerycznie nie mogą być katastroficzne w skutkach. Przykładem może być tutaj eksplozja rakiety wartej 500 milionów dolarów Ariane 5. Przyczyna? Błąd konwersji liczby zmiennoprzecinkowej (64 bity) na całkowitą (16 bitów) i rzucenie wyjątku przez system. Głupia rzecz? Jak widać nie. Drugim przykładem może być system PATRIOT który w 1991 roku zawiódł, co kosztowało życie 28 amerykańskich żołnierzy. Gdy zegar baterii (trzymany jako liczba całkowita) osiągał duże wielkości, przy konwersji na liczbę zmiennoprzecinkową powodowało spory błąd. Pewnego dnia system działał od 100 godzin pociągając za sobą błąd 1/3 sekundy. To natomiast przełożyło się na uderzenie 700 metrów od pierwotnego celu! Można było tego uniknąć, bo aby system działał poprawnie wystarczyło restartować go co kilka godzin. Co ciekawe, Amerykanie wiedzieli o luce, a aktualizacja była w drodze - niczym w (amerykańskim) dramacie hollywoodzkim dotarła dzień za późno.

Wpis zainspirowany oraz oparty jest w dużej mierze na wykładzie dr Pawła Woźnego, dotyczącego analizy numerycznej.  

programowanie inne

Komentarze

0 nowych
  #1 27.11.2013 09:38

Odkrycie na miarę NOBLA

  #2 27.11.2013 10:40

Komputer potrafi liczyć tylko problem pojawia się przy konwersji z dziesiętnego na binarny i w drugą stronę

mati75   6 #3 27.11.2013 10:42

Zastanawia mnie jedno, dlaczego używasz float zamiast double w przypadku takiej liczby.

dzikiwiepsz   12 #4 27.11.2013 11:03

Zadziwiające, myślałem że komputer w liczbach jest geniuszem a tu taka informacja że robi takie byki.

tomem92   2 #5 27.11.2013 11:06

@mati75 czepiasz się szczegółów ;) kubut chciał dać komputerowi do dyspozycji nieco więcej pamięci na liczby, ale to nie ma wielkiego wpływu na działanie programu. równie dobrze można by zastanawiać się, dlaczego nie dodał using namespace std; dlaczego używał Dev C++, po co te argumenty do maina() itd. itd.
ale liczy się poruszony problem i jego świetny opis na prostych przykładach ;)

  #6 27.11.2013 11:30

Tania sensacja. Taki jest tytuł jak i sama treść. Każdy programista bawiący się liczbami zmiennoprzecinkowymi powinien to wiedzieć.
Oczywistym jest to, że konwersja między int a float nie jest dokładna i należy się z tym liczyć. A komputerów używać przede wszystkim świadomie.

kubut   18 #7 27.11.2013 12:42

Jak pisałem nie jest to wiedza tajemna i faktycznie na większości uczelni informatycznych jest to poruszane. Ale zauważmy, że nie na wszystkich. Nie każdy też jest po studiach. Nie rodzimy się z taką wiedzą, a jest to ciekawe, więc czemu by tego nie opisać? :-)

  #8 27.11.2013 12:51

Ale to nie chodzi o to, że powtarzamy odejmowanie 100 razy w pierwszym przykładzie i to czy odejmiemy 1000 czy 10*100 to wyjdzie taki sam wynik. Jaki jest tego powód? Ano taki, że 0,1 nie ma skończonego rozwinięcia w systemie binarnym oraz zapis maszynowy ma ograniczoną ilość miejsca. Dodajmy do tego utratę cyfr znaczących i nam wszystko ładnie się wyjaśnia.

tfl   8 #9 27.11.2013 13:08

Obiecalem sobie, ze przestane sie denerwowac czytajac blogi na dp.pl... obiecalem sobie i slowa nie dotrzymalem.

Wpis jest merytorycznie wyssany z palca. To nie komputer ma problemy z trywialnymi operacjami matematycznymi, tylko autor ma zaleglosci w wiedzy matematycznej nabywanej w okresie szkoly podstawowej, kiedy to mowi sie o liczbach naturalnych i ulamkach przyprawiona brakami zwiazanymi wiedza na temat typow danych w informatyce.

Ten sam "problem" pojawil sie juz w tym wpisie: http://www.dobreprogramy.pl/slepciu/Dlaczego-w-MySQLu-nie-stosowac-typu-FLOAT,30... w ktorym autor tego rowniez sie wypowiadal

  #10 27.11.2013 13:27

Dokładnie tak jak pisze tfl:
brak podstawowej wiedzy u autora i u niektórych komentatorów.

kostek135   8 #11 27.11.2013 13:46

@kubut
"Jak pisałem nie jest to wiedza tajemna i faktycznie na większości uczelni informatycznych jest to poruszane. Ale zauważmy, że nie na wszystkich. Nie każdy też jest po studiach. Nie rodzimy się z taką wiedzą, a jest to ciekawe, więc czemu by tego nie opisać? :-)"

To naprawdę trzeba być po studiach, żeby wiedzieć, że zbioru skończonego (2^n stanów, gdzie n jest liczbą bitów) nie można wykonać bijekcji na zbiór nieskończony (np. przedział ) ?

kubut   18 #12 27.11.2013 13:46

@Informa-tyczka - nadmienilem co jest tego powodem, jednak celem tego wpisu nie było dokładne opisanie zjawisk, a jedynie pokazanie ze takowe mają miejsce :-)

@tfl - ktoś za to ma braki z czytania ze zrozumieniem, bo już na samym początku wpisu nadmieniam, że "wine" ponosi niemożność zapisu dowolnej liczby ulamkowej w pamięci komputera. A skoro nie możemy uzyskać dokładnego wyniku trywialnych działań, to znaczy ze mamy jakiś problem z nimi. Tutaj problemem jest reprezentacja liczb i pochodne tego. Ale przekłada się to ma problem z wykonywaniem działań.

Jeśli chodzi o "każdy o tym wie " to polecam ostatni akapit, który pokazuje że nie każdy wie. Przykłady stare, ale gdyby nigdzie nie publikować materiałów o tym bo "każdy to wie ", nie widziałby o tym nikt do czasu kolejnej tragedii...

kostek135   8 #13 27.11.2013 13:46

np. przedział [0,1]* (dlaczego usuwa znaki mniejsze/większe?)

kubut   18 #14 27.11.2013 13:51

Na telefonie nie umiem edytować komentarza (a chyba się dało?) więc piszę jeden pod drugim.

@kostek - dlatego nie opisywałem tych zjawisk, bo nie są magiczne. Kwestia tego ze często się o tym zapomina jeśli nigdy nie zwróciło się na to uwagi. Na podobnej zasadzie moznaby nie pisać nic, bo 90% wpisów nie odkrywa czegoś nowego (bo nie od tego jest blog żeby odkrycia naukowe tworzyć )

  #15 27.11.2013 14:00

@tfl @mmm777
Hmmm autor wpisu nie dziwi się, że tak jest, tylko pokazuje, że tak jest, o co chodzi i że wynika to z błędów zaokrągleń (skończonej dokładności liczby w dedykowanym dla niej obszarze pamięci) jak i ograniczeń binarnego zapisu liczby. Jest nawet porównanie do bardzo prostego przykładu zapisu liczby 1/3 w systemie dziesiętnym (1/3 = 0,3333333, w sumie da się dokładnie 0,(3) ale to szczegół i nie zmniejsza poprawności prezentowanej treści). Akapit pod nagłówkiem "Więc w czym problem" - czytali Panowie?

Co takiego konkretnie niemerytorycznego jest w tym opisie?

Problemem nie jest fakt, że liczby się tak konwertują pomiędzy systemami zapisu (binarny -> dziesiętny), bo to jest ich cecha. Błędem jest tylko brak wiedzy o tym. Autor nie wiedział o tym w lutym 2012 (jak zauważa tfl) a teraz wie i innym wiedzę swoją przekazuje. A że to proste rzeczy - racja. Tylko co z tego, naukę zaczyna się od podstaw.

PS. jak bym się czepiał to bym napisał, że warto dodać linki do wspomnianej Wikipedii skoro już się do niej odwołujesz :P

oprych   13 #16 27.11.2013 14:42

@kubut nie przejmuj się, jak ktoś ma manie wyższości lub nie potrafi czytać ze zrozumieniem, to jego kłopot :)

sgj   11 #17 27.11.2013 14:48

Czy komputer potrafi liczyć? Zdaje się że potrafi

using System;

namespace ConsoleApplication3
{
class Program
{
static void Main(string[] args)
{
decimal x = 1000.1M;
int i;
for (i = 0; i < 100; i++)
{
x = x - 10;
}
Console.WriteLine(x);
Console.ReadLine();
}
}
}

Output:
0,1

d4rqu   3 #18 27.11.2013 14:52

zamiast pisać bezsensowne funkcje, kliknijcie sobie dzieci na start -> uruchom
wpiszcie: calc
następnie
1000.1-1000 =

i jaki wynik? ano 0.1 wiec komputer dobrze liczy ;p

tfl   8 #19 27.11.2013 15:09

Nie, to nie wynika z problemu zapisu w pamięci (whatever) komputera, tylko z faktu, że takie są prawa arytmetyki zmiennoprzecinkowej. Liczba zmiennoprzecinkowa jest _zawsze_ podana w przybliżeniu, trzeba więc operacje matematyczne przeprowadzać należy wiedząc o tym i stosując funkcje, które potrafią ogarnąć fakt tego przybliżenia.

Generalnie polecam lekturę: http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

Dzielenie 1/3 sprawia problemy? W systemie dwójkowym to przecież wciąż podobna liczba: 0,(01)

tfl   8 #20 27.11.2013 15:17

BTW, cała ta sytuacja nieodparcie kojarzy mi się z czasami, kiedy to zaćmienie słońca tłumaczono zdenerwowaniem bogów, większość słuchających przyjmowała to za dobrą monetę, a tłumaczących nazywano prorokami.

kubut   18 #21 27.11.2013 15:43

@tfl - skończ, wstydu (sobie) oszczędź. Nigdzie nie napisałem ze dzielenie 1/3 sprawia problemy, problematyczny jest zapis wyniku jawnie (bez trików w postaci okresu).

tfl   8 #22 27.11.2013 15:52

@kubut

zastanawiam sie skad przyszlo ci do glowy, ze tym razem moje slowa byly do ciebie skierowane?

Te slowa sa do ciebie:

"Pytanie brzmi: czy oby na pewno kolejność dodawania nie ma znaczenia?" Odpowiedz: Tak, ma znaczenie. Arytmetyka zmiennoprzecinkowa nie jest laczna i rozlaczna.
Potem piszesz: "Niby nic złego się nie powinno stać, ale zerknijmy na wyniki" Potrzebowales doprawy wynikow, zeby to wiedziec?

Oto jak zapisac jawnie dzielenie 1/3: 1 reszty 2.

Calosc tego tekstu przesiaknieta jest brakiem wiedzy o zmiennoprzecinkowych liczbach. Pozwole sobie na przypuszczenie, ze liczby zmiennoprzecinkowe mylisz z ulamkami.

kubut   18 #23 27.11.2013 16:03

@tfl - wiec jeszcze raz powtarzam Ci, że tekst nie jest objawem mojego zdziwienia. Nie wiem na jakiej podstawie wnioskujesz, że podanie przykładów na których łatwo się "wyłożyć " bez odpowiedniej wiedzy, traktujesz jako brak takowej wiedzy? Czy napisałem "nie wiem czemu tak się dzieje, magia jakas "? Nie. Wyraźnie napisałem ze ma to swoje uzasadnienie teoretycznie ale nie będę go przytaczal.

floyd   15 #24 27.11.2013 16:03

Ja jednie czepiał bym się sformułowań typu: "Czy komputer potrafi liczyć? Okazuje się, że nie!"
i określeń typu błąd, pomyłka itp. W potocznym rozumieniu błąd to coś co można naprawić bo jest wynikiem jakiegoś niedopatrzenia. Tutaj nic nie można naprawić czyli nie jest to błąd czy jakieś niedopatrzenie programisty, a tak niektórzy czasami sądzą.
Nie tak dawno widziałem na forum pytanie dlaczego: Dlaczego mój Excel źle liczy i tu były przykłady podobne do tych tu opisanych.
Mówi się, że komputer jest tak mądry jak programista który napisał konkretny program. Programista pisząc program pisze go pod konkretne potrzeby uwzględniając jednocześnie możliwości sprzętu, które nie są nieograniczone. Przeciętny użytkownik komputera też powinien sobie z tego zdawać sprawę i dlateo czasami warto tym pisać.

kubut   18 #25 27.11.2013 16:21

@floyd - tytuł jest z przymrużeniem oka, może faktycznie trochę zmyla na start :-) natomiast określenie błąd moim zdaniem jest wporzadku dopóki rozmawiamy w gronie informatycznym :-) szczególnie ze czasami błędny wynik może być spowodowane ignorancja programisty (np liczenie pierwiastków równania kwadratowego ze szkolnych wzorów. Można wynik poprawić odpowiednim trikiem). Choć oczywiście przy rozmowie z klientem lepiej unikać slowa błąd :-P

mikolaj_s   14 #26 27.11.2013 16:36

@tfl:
"Calosc tego tekstu przesiaknieta jest brakiem wiedzy o zmiennoprzecinkowych liczbach. Pozwole sobie na przypuszczenie, ze liczby zmiennoprzecinkowe mylisz z ulamkami."

Zazdrościsz, że ktoś to fajnie opisał? Pokaż gdzie w prezentowanych zagadnieniach jest błąd logiczny. Akurat mam kontakt z początkującymi programistami i wiem, jak ciężko jest im na początku ogarnąć co może ich spotkać ze strony liczb zmiennoprzecinkowych. Tutaj mają ciekawie opisany problem, choć nie jest to wykład naukowy. Można by jeszcze dodać, że wyniki mogą zależeć od kompilatora, języka programowania i maszyny, bo zależą od sposobu implementacji zmiennych rzeczywistych.
Na szczęście komputer to tylko maszyna i faktycznie nie da się powiedzieć, że potrafi liczyć (co coś tam potrafi, ale do człowieka mu daleko), bo liczenie to nie tylko proste operacje arytmetyczne, a również analiza matematyczna. ;)

"Oto jak zapisac jawnie dzielenie 1/3: 1 reszty 2. "

Nie pojmuje tej wyższej matematyki ;) Na mój rozum to 0 reszty 1 z dzielenia przez 3

  #27 27.11.2013 17:41

Dzięki za wpis. Teraz podstaw programowania uczy się na wielu kierunkach studiów na politechnikach, nie tylko takich jak informatyce, elektronice i telekomunikacji. Jestem na wydziale mechanicznym i mam programowanie m.in. sterowników PLC. Nie mam za to właśnie takiej wiedzy, jaka jest w artykule. Kto wie, być może będę za jakiś pisał jakiś program dla jakiegoś systemu w przemyśle i wtedy będę bardziej świadomy dzięki Twojemu wpisowi.
Pozdrawiam

tfl   8 #28 27.11.2013 18:00

@kubut

W twoim tekscie pojecie liczby zmiennoprzecinkowej pada dopiero w podsumowaniu, w ktorym pokazujesz jakie niesie ze soba konsekwencje nieumiejetne stosowanie floatow. A przez caly tekst stosujesz ogolne pojecie liczba. Przez to sprawiasz wrazenie, ze opisywane przez ciebie przypadki dotycza liczb wszystkich, a tak przeciez nie jest. Oczywiscie nigdzie w tekscie nie pada nawet jedno slowo o innych typach liczb, na ktorych te operacje by sie nie powiodly (w pierwszym przykladzie mozna by zastosowac liczbe staloprzecinkowa z powodzeniem, a wynik bylby zgodny z oczekiwanymi).

Czy z twojego tekstu dowiaduje sie dlaczego tak sie dzieje? Czy z twojego tekstu dowiaduje sie, jak mozna bylo uniknac problemu patriotow? Czy naprawde problemem bylo uzycie liczby zmiennoprzecinkowej, a moze problemem bylo zanizenie precyzji tej liczby? Co to jest w ogole ta precyzja?

Moim zdaniem z twojego tekstu nie dowiaduje sie niczego z tego, co wymienilem. Dlatego dalej uwazam, ze przedstawione przyklady sa podobne do jarmarcznych iluzji - nastawione na tani poklask niskim kosztem.

@mikolaj_s

W kontekscie tego co napisalem przed momentem - w tekscie nie ma mowy za wiele o liczbach zmiennoprzecinkowych... Co do dzielenia z reszta... no coz... taki honeypot, ale na Twoim miejscu bym sobie nie uwierzyl.

kubut   18 #29 27.11.2013 18:12

@tfl - istotnie nie dowiadujesz się o niczym z tego co napisałeś. Zresztą wyraźnie zaznaczyłem na początku ze się tego nie dowiesz, bo nie taki był cel tekstu. Tylko znajdź mi kuglarza który przy wykonywaniu sztuczki mówi "to nie magia, tylko złudzenia optyczne które łatwo znaleźć w internecie". Rozumiem że nie odpowiada Ci brak wyjaśnień tych zjawisk, jestem w stanie to zaakceptować - to Twoja opinia o tekście. Ale nie widzę w tym podstawy do nazywania mnie kuglarzem, iluzjonista albo prorokiem.

wajdzik   6 #30 27.11.2013 18:58

Dla informatyków jest to wiedza oczywista. Dla kogoś kto nie ma pojęcia o liczbach binarnych jest to bardzo ciekawy temat.

Z tego typu ciekawostek - ludzie też nie potrafią liczyć.
1/3+1/3+1/3=1
1/3=0.(3)
0.(3)+0.(3)+0.(3)=0.(9)
1=0.(9)

  #31 27.11.2013 19:25

@wajdzik - Ludzie potrafią liczyć, bo 0,(9) to jest faktycznie to samo co 1.

  #32 27.11.2013 19:32

Kubut
podstawę logarytmu naturalnego obliczyłeś i zapisałeś na kartce (dokładnie)? jak nie to nie naśmiewaj się z komputera, że "ułomny" jest wynalazek człowieka.
Co do awarii to jakby tym co odpowiedzialni są chciało się ruszyć swoje szanowne cztery litery i rozwiązać problem od razu, to obyłoby się bez ofiar.

Frankfurterium   10 #33 27.11.2013 19:45

Jedna z tych rzeczy, o których trzeba pamiętać przy zabawie językami stosunkowo-niskopoziomowymi. Przy współczesnych narzeczach to maszyna wirtualna dba o precyzję i wydajność takich działań. Przy jeszcze nowszych językach 1/3 to naprawdę 1/3 (ułamek zwykły), a nie 0.33333...

  #34 27.11.2013 20:01

@kubut

Z tymi rakietami to już trochę poleciałeś..
Programiści pracujący przy takich projektach to nie żółtodzioby.
A każdy programista który ma JAKIEKOLWIEK doświadczenie i choćby MINIMALNĄ wiedzę, wie co to są liczby zmiennoprzecinkowe i jakie wynikają z tego ograniczenia. Do zniwelowania błędów używa się liczb zmiennoprzecinkowych podwójnej precyzji. A tam gdzie absolutnie nie może zajść pomyłka wynikająca z zaokrąglenia ( obliczenia finansowe, sterowanie mega wypaśnymi rakietami, czy super niszczycielskimi pociskami jądrowymi), stosuje się liczby stałoprzecinkowe (tak, liczby stałoprzecinkowe dla ułamków).
Nie każdy jest po studiach informatycznych - zgoda. Ale jeśli ktoś już jest na takich studiach i nie wie co to są liczby zmiennoprzecinkowe i jak działają i co z tego wynika, to powinien udać się do dziekanatu i poprosić o skreślenie. I poprosić o zwrot kosztów czesnego. A to że poziom uczelni jest z roku na rok coraz słabszy to też mnie nie dziwi - w końcu jak po kolejnych reformach systemu edukacji studenci pierwszego roku uczelni technicznej nie do końca wiedzą co to jest cosinus, to jakby nie ma co dalej rozmawiać.
Natomiast jeśli ktoś nie jest na studiach a zabiera się za programowanie, to warto zacząć od podstaw: Teorii automatów, arytmetyki systemów cyfrowych, budowy procesora, podstaw algorytmów, a dopiero potem brać się za poważne programowanie.

Dlatego sugerował by zmianę tytułu.
Bo podane przykłady do niego nie pasują. Komputer robi dokładnie to co mu się każe. Jeśli programista nie umie liczyć, i pisze tak jak pisze a spodziewa się czegoś innego to już jest wina programisty a nie komputera.
Dlatego kubut - proponuję zmienić ten tytuł, na jakiś mniej obciążający winą komputer.
Ale chwała Ci za poruszenie tematu - niech to będzie przestroga dla tych którzy po przeczytaniu trzech rozdziałów pierwszego podręcznika do programowania w weekend są od razu programistami.

kubut   18 #35 27.11.2013 20:39

@wajdzik - dla informatyków "zawodowych" zapewne tak, ale dla hobbystów często nie jest to takie oczywiste :) Zapewniam Cię, że na pierwszym wykładzie z analizy numerycznej znaczna część studentów była zaskoczona (w tym ja) tymi błędami :) I nie wynikało to z niewiedzy nt. liczb binarnych. Tak jak podany przez Ciebie przykład również jest w jakiś sposób zaskakujący dla osób widzących go pierwszy raz, mimo że jest trywialny :) Swoją drogą, moja "matematyczka" w szkole średniej była zaskoczona jak ją o to 1=0.(9) zapytaliśmy... Wiem że to nie najlepiej świadczy o szkole, ale co zrobić :D

eddie71   8 #36 27.11.2013 21:25

Wszyscy mają rację.
Tytuł bloga trochę niefortunny.
Oczywiście komputer może podać niewłaściwy wynik.
Jednak to są błędy ludzkie.
Ten, kto zna mechanizmy działania komputera wie jakie są konsekwencje niewłaściwie postawionych zadań.
Dla początkujących takie ostrzeżenie może się przydać w przyszłości.

[ 1+1=10 ]

Wokuo   7 #37 28.11.2013 00:19

@kubut - jednak trzeba było przepisać tą Wikipedię

http://pl.wikipedia.org/wiki/Liczba_zmiennoprzecinkowa
Trzecie zdanie w artykule na Wikipedii jest odpowiedzią na pytanie w tytule twojego wpisu - "Powoduje to, że reprezentacja liczby rzeczywistej jest tylko przybliżona, a jedna liczba zmiennoprzecinkowa może reprezentować różne liczby rzeczywiste z pewnego zakresu."

Komputer umie liczyć i robi to zdecydowanie lepiej niż my, ludzie. Tu jako przykład mogę podać obliczenia fizyczne wykonywane przy okazji różnych badań kosmosu. W przypadku takich badań operację trwają zdecydowanie wolnej i potrzebują więcej zasobów systemowych by wyniki były jak najdokładniejsze. Natomiast zadaniem float'a jest podanie jak najdokładniejszego wyniku przy jak najmniejszym zużyciu zasobów. Jak już, któryś z poprzedników zauważył chce dokładny wynik korzystaj z liczb stałoprzecinkowych.

Według mnie wpis próbuje potwierdzić z góry ustaloną tezę przy okazji wprowadzając ludzie nie obeznanych z tematem w błąd. Nieprecyzyjne wyniki float'a nie są w żadnym wypadku błędem komputera. Co innego, jeśli programista nie ma pojęcia do czego służy ten typ danych i jak działa.
Niestety po twoim wpisie raczej spodziewałbym się fali postów na FB/Twitterze, że komputery nie potrafią liczyć niż zwiększenia świadomości wśród programistów.

Podsumowanie mojego komentarza może być stwierdzenie:
TEN TYP TAK MA

PS.
@eddie71
Odnośnie 1+1=10, taki suchar na koniec:
"Ludzi na świecie można podzielić na 10 rodzajów. Tych, którzy rozumieją liczby binarne oraz tych, którzy ich nie rozumieją."

mikolaj_s   14 #38 28.11.2013 07:34

@Wokuo: "Komputer umie liczyć i robi to zdecydowanie lepiej niż my, ludzie"

Komputer nie potrafi liczyć, to tylko maszyna. Realizuje tylko pewne działania arytmetyczne, według określonych zasad, które trzeba poznać. Im szybciej student przestanie personifikować komputer tym szybciej zacznie go poprawnie używać.

@ _Michał_S_ "Natomiast jeśli ktoś nie jest na studiach a zabiera się za programowanie, to warto zacząć od podstaw: Teorii automatów, arytmetyki systemów cyfrowych, budowy procesora, podstaw algorytmów, a dopiero potem brać się za poważne programowanie. "

Tak, a jak chce sobie zrobić piwo z brewkita to najpierw muszę poznać całą chemię spożywczą. Czy aby nie przesadzasz? Student też nie przychodzi od razu z wiedzą i musi mieć trochę czasu na jej opanowanie, a programowanie zaczyna zanim zapozna się dogłębnie z teorią. To jakbyś mówił, chłopie naucz się najpierw pływać to naleję ci wody do basenu :-)

"Dlatego kubut - proponuję zmienić ten tytuł, na jakiś mniej obciążający winą komputer"

A dlaczego? Każdy myślący, a nie wiedzący o co chodzi będzie miał szanse dociekać i dowiedzieć czegoś nowego. Komputer bez problemu zniesie obarczanie go winą i nie obrazi się :-) Na pytania dlaczego mój arkusz kalkulacyjny nie potrafi liczyć trzeba dać odpowiedż, ze to jest maszyna, a nie cudowny genialna istota matematyczna jak widzą go niektórzy laicy.

mikolaj_s   14 #39 28.11.2013 08:53

@wajdzik:
"Z tego typu ciekawostek - ludzie też nie potrafią liczyć.
1/3+1/3+1/3=1
1/3=0.(3)
0.(3)+0.(3)+0.(3)=0.(9)
1=0.(9)"

Pomijając fakt, że jest to jak najbardziej prawdziwa równość, a propos komputera na JVM:
1.0/3.0 = 0.3333333333333333 (typ double)
ale po pomnożeniu razy trzy daje nam 1.0 , więc nie taki głupi ten komputer ;) (dla float też zadziała)

stasinek   11 #40 28.11.2013 11:55

Czy ludzie potrafią czytać ze zrozumieniem? Okazuje się że nie.
Czy problem liczb jest poważny - okazuje się że tak co można stwierdzić po przeczytaniu niektórych jeśli nie wiekszości komentów. Double rozwiązaniem heh
...0.33333 liczbą niewymierną - w zapisie binarnym nawet 0.1 jest liczbą niewymierną!
o czym znający problem i jego przyczyny powinni wiedzieć.
mam taką nadzieje ;)

  #41 28.11.2013 12:05

0.(9)*10=9.(9)
9.(9)-0.(9)=9=9*0.(9)
0.(9)=1

Jaahquubel_   13 #42 28.11.2013 13:43

Błąd rzędu 1e-4 - 1e-5 nie jest małym błędem. Małym błędem jest błąd rzędu 1e-16.
Zobacz jeszcze (11/10-1)*10-1 i (4/3-1)*3-1.

kubut   18 #43 28.11.2013 14:40

@Jaahquubel_ - błąd określiłem jako "mały" w rozumieniu potocznym, bo na pierwszy rzut oka błąd na którymś tam miejscu po przecinku może wydawać się mały, jednak faktycznie od strony analizy poprawności jest to błąd drastyczny, bo znacznie większy niż błąd na poziomie reprezentacji

mikolaj_s   14 #44 28.11.2013 15:07

@stasinek: Zamiast narzekać na innych lepiej sam poczytaj. Liczba 0,(3...) jeśli Ci o nią chodziło jest wymierna. Nie ma tylko skończonego rozwinięcia w systemie dziesiętnym. Za to ma skończoną postać w systemie trójkowym, szóstkowym itp. Liczba 0.1 jest również wymierna niezależnie od systemu liczbowego tylko w zapisie binarnym nie ma skończonego rozwinięcia.
Problem jest o tyle poważny, o ile ludzie nie będą go świadomi.

mikolaj_s   14 #45 28.11.2013 15:14

@Jaahquubel_
"Błąd rzędu 1e-4 - 1e-5 nie jest małym błędem. Małym błędem jest błąd rzędu 1e-16.
Zobacz jeszcze (11/10-1)*10-1 i (4/3-1)*3-1."

Na JVM dla typu double:
(11.0/10.0-1.0)*10.0-1.0 = 8.881784197001252E-16
(4.0/3.0-1.0)*3.0-1.0 = -2.220446049250313E-16
Czyli zgodnie z Twoją definicją mały błąd ;)

mikolaj_s   14 #46 28.11.2013 15:15

@Jaahquubel_
"Błąd rzędu 1e-4 - 1e-5 nie jest małym błędem. Małym błędem jest błąd rzędu 1e-16.
Zobacz jeszcze (11/10-1)*10-1 i (4/3-1)*3-1."

Na JVM dla typu double:
(11.0/10.0-1.0)*10.0-1.0 = 8.881784197001252E-16
(4.0/3.0-1.0)*3.0-1.0 = -2.220446049250313E-16
Czyli zgodnie z Twoją definicją mały błąd ;)

mgr.inz.Player   6 #47 28.11.2013 17:10

Wszystko rozchodzi się o to że "typ" single, double i inne to tak na prawdę zbiory liczb.
pisząc:

double g = 9.81;

"informujemy" komputer aby wybrał ze zbioru "double" wartość, która jest najbliższa tej podanej po prawej stronie znaku przypisania i umieścił ją w zmiennej g. Z pomocą jedenastu bitów przeznaczonych na wykładnik i pięćdziesięciu dwóch bitów przeznaczonych na mantysę, liczba zapisana jest jako 9.8100004.......

Aby uniknąć błędów po prostu należy korzystać z odpowiedniego zbioru liczb. Po to istnieją "dodatkowe" typy (zbiory) jak "currency", "decimal", "date" i wiele wiele innych typów. Gdy użytkownik jest tego świadomy i potrafi używać odpowiednich typów, to okazuje się że "komputer potrafi liczyć" i to całkiem dobrze.

Jeszcze pamiętam jak używało się przełącznika {$n+} oraz typów Double i Extended w Turbo Pascalu. Robiło się symulację ciał niebieskich :D

Dużo groźniejsze są błędy tego typu, tj. źle zaprojektowany sprzęt do obliczeń:
http://en.wikipedia.org/wiki/Pentium_FDIV_bug

Wokuo   7 #48 28.11.2013 20:49

@mikolaj_s
"Komputer nie potrafi liczyć, to tylko maszyna. Realizuje tylko pewne działania arytmetyczne, według określonych zasad, które trzeba poznać."

Hmmm... W takim razie jak liczy człowiek? Zawsze wydawało mi się, że licząc wykonuje pewne działania arytmetyczne takie jak dodawanie czy mnożenie. Tu Cię może zaskoczę, ale wykonując te pewne działania arytmetyczne też stosuję określone zasady, może kojarzysz kolejność wykonywania działań.

Nie rozumiem o co Ci chodzi z personifikowaniem komputera. Zgodzę się z tobą, że komputer to tylko maszyna. O ile dobrze pamiętam, to komputery zostały stworzone właśnie po to by wykonywały obliczenia i śmiem twierdzić, że to potrafią.

mikolaj_s   14 #49 29.11.2013 23:01

@Wokuo:
Wydaje mi się, że głównie różnica polega na tym, że człowiek ma jednak większe możliwości myślenia abstrakcyjnego. Jak mówią specjaliści najlepsze superkomputery maja obecnie moc obliczeniową szczura (więc w sumie niedaleko już do człowieka). Posiada też zdolność do samouczenia i doskonalenia, może więc zauważyć błąd w swoim rozumowaniu i wyjść poza schemat.

Personifikacja to liczenie na to, że komputer jest mądrzejszy od człowieka skoro tak szybko liczy. Jako programista musisz wiedzieć jaki jest schemat jego działania i nie liczyć na to, że zrobi coś samodzielnie. To w końcu na razie my programujemy komputery, a nie one nas.

kubut   18 #50 30.11.2013 01:42

"To w końcu na razie my programujemy komputery, a nie one nas."
...jeszcze :P

Wokuo   7 #51 02.12.2013 00:41

@mikolaj_s

Wydaje mi się, że trochę źle zinterpretowałeś moją poprzednią wypowiedź.
Jak napisałem w poprzednim poście komputery zostały stworzone do wykonywania obliczeń. Podobnie jak inne urządzenia czy maszyny komputer ma wykonywać to do czego został stworzony i zazwyczaj ma robić to lepiej od nas. Jako przykład mogę podać samochód. Został on stworzony do łatwiejszego i szybszego przemieszczania się. Podobnie jest z komputerem, ma on wykonywać obliczenia szybciej od nas.

Jeśli maszyny/urządzenia nie są wydajniejsze od nas to w jakim niby celu je budujemy?

Zanim zaczniesz rozważać czy komputer jest mądrzejszy od człowieka, zastanów się czy komputer posiada samoświadomość. Według mnie jej nie posiada, więc takie porównanie jest bezsensowne.

W żadnym wypadku nie liczę na to, że komputer zrobi coś samodzielnie. Niestety znam też schemat jego działania. Został on opracowany przez ludzi i przez ludzi musi być zrozumiały.

@kubut
Słuszna uwaga. Mam nadzieję, że taka sytuacja nigdy nie będzie miała miejsca.

TomaszK-Poz   8 #52 02.12.2013 01:39

@mgr.inz.Player

Pięknie opisane !

  #53 19.04.2015 21:20

Matko święta w niebo wzięta...
set/a k=1000
set/a x=100
set/a x*=10
set/a k-=%x%
echo %k%
pause>nul

I vuala, program obliczył to, co autor uznał za niemożliwe :P