Wątek zablokowany 2018-05-05 18:41 przez Patryk27.

jakieś straszne błędy w obliczeniach numerycznych!

0

Obliczam w kalkulatorze w Windows 7:
sqrt(4) - 2,
wynik jest oczywiście 0, no ale ten kalkulator podaje mi:
-8.1648465955514287168521180122928e-39

tak samo jest z innymi tego typu obliczeniami:
sqrt3(8) - 3 = 5.1270228572945803251046807541983e-38
sqrt4(16) - 4 = 2.3385898542599420020875787886029e-38

sqrt9 - 3 = 1.1546388020691628168216106791278e-37
sqrt100 - 10 = -8.540347346306588893911223888183e-38

sqrt(2^2)-2 = 1.1578739678741186722221088213213e-37
ln128 / ln2 - 7 = 7.878240562869717014844322177209e-38

Czy to jest źle zaprogramowane?
Procesory chyba nie popełniają aż tak głupich błędów, np. sqrt4 = 2 dokładnie, a nie jakieś 1.99999999999999999.

0

Może ktoś wyjaśni to dokładniej, ale ja proste wyjaśnienie znalazłem tutaj:
https://blogs.msdn.microsoft.com/oldnewthing/20160628-00/?p=93765

Chodzi o to, że kalkulator w Windowsie traktuje obliczanie pierwiastka jako, hm, "działanie zaawansowane" (advance operation, jak stoi w artykule). Co za tym idzie, używa innej arytmetyki do obliczania pierwiastków niż na przykład do dodawania czy odejmowania. Ze wzoru w artykule wynika, że przy obliczaniu pierwiastka brany jest pod uwagę logarytm naturalny. Dlatego też -8.1648465955514287168521180122928e-39 jest jedynie przybliżeniem zera.

1

Wszystko spoko, tylko że niestety raczej nie przez ten logarytm się to psuje (bo na IEEE 32-bit float wzorek działa jak należy, i exp(ln(4)/2) to dokładnie 2.

Innymi słowy, problem leży głębiej.
Jeśli exp(ln(4)/2) == 2 we floatach (jak i w double), no to można oczekiwać, że wynik zostanie dokładnie zinterpretowany jako 2 (w arytmetyce dowolnej precyzji). Jeżeli tak się nie dzieje, to błędne jest zrobiony konwerter. Jeżeli jednak się tak dzieje, to nie ma powodów, aby 2-2!=0

Co więcej, w późniejszych wersjach błąd został naprawiony: https://www.windowslatest.com/2018/04/05/microsoft-fixes-a-long-standing-windows-calculator-bug-in-latest-windows-10-build-17639/

0
Silv napisał(a):

Może ktoś wyjaśni to dokładniej, ale ja proste wyjaśnienie znalazłem tutaj:
https://blogs.msdn.microsoft.com/oldnewthing/20160628-00/?p=93765

Chodzi o to, że kalkulator w Windowsie traktuje obliczanie pierwiastka jako, hm, "działanie zaawansowane" (advance operation, jak stoi w artykule). Co za tym idzie, używa innej arytmetyki do obliczania pierwiastków niż na przykład do dodawania czy odejmowania. Ze wzoru w artykule wynika, że przy obliczaniu pierwiastka brany jest pod uwagę logarytm naturalny. Dlatego też -8.1648465955514287168521180122928e-39 jest jedynie przybliżeniem zera.

Jakieś to chore - amatorszczyzna?

Nie wyobrażam sobie jak można produkować błędy w binarnej arytmetyce na pierwiastkach.

16 = 2^4, zatem nie ma tu nawet szans na popełnienie błędu w obliczaniu pierwiastka.
sqrt(2^4) = 2^2 * 1 - sam zapis floatów to załatwi!
sqrt(2^2) = 2^1 * 1
itd.

0
enedil napisał(a):

Wszystko spoko, tylko że niestety raczej nie przez ten logarytm się to psuje (bo na IEEE 32-bit float wzorek działa jak należy, i exp(ln(4)/2) to dokładnie 2.

Innymi słowy, problem leży głębiej.
Jeśli exp(ln(4)/2) == 2 we floatach (jak i w double), no to można oczekiwać, że wynik zostanie dokładnie zinterpretowany jako 2 (w arytmetyce dowolnej precyzji). Jeżeli tak się nie dzieje, to błędne jest zrobiony konwerter. Jeżeli jednak się tak dzieje, to nie ma powodów, aby 2-2!=0

Co więcej, w późniejszych wersjach błąd został naprawiony: https://www.windowslatest.com/2018/04/05/microsoft-fixes-a-long-standing-windows-calculator-bug-in-latest-windows-10-build-17639/

Ale czy na pewno?

Sprawdź np. takie coś:
log(1000000) - 6 = ?
arctan(1) - pi/4 = ?
sqrt(2)*sqrt(2) - 2 = ?

0

Nie stwierdziłem, że tak się dzieje zawsze, to co powiedziałem jest bardzo konkretne - w liczbach zmiennoprzecikowych, jeśli da się dokładnie przedstawić zarówno x jak i sqrt(x), to sqrt(x)^2 == x.
Dzieje się to ponadto mnie aż tak rzadko:

import numpy as np
l = np.random.exponential(2, 1000000)
(np.exp(np.log(l**2)/2) == l).sum() # 811346

Procent ten staje się mniejszy wraz z wzrostem liczb, aczkolwiek pozostaje znacząco niezerowy.

3

Ale w ogóle, czego się czepiacie -- błędy w obliczeniach zmiennoprzecinkowych są naturalne i wręcz "wrodzone" w ten typ. Nie da się inaczej... Weźcie uruchomcie sobie ulubiony język/interpreter/kompilator i sprawdźcie:

>>> 0.1 + 0.2 == 0.3
False

(u mnie to akurat Python 3.4.2, ale w gcc 6.3.0 jest to samo).

Ktoś kiedyś powiedział, że komputery nie nadają się do obliczeń... :)

0

Błędy są, ale jednak są sytuacje, gdzie standard gwarantuje poprawność wyników. Chyba nie jest naszym celem stwierdzić "wszystko może się zdarzyć", odpowiedź którą chcemy ma być najdokładniejsza jak się da.

0
koszalek-opalek napisał(a):

Ale w ogóle, czego się czepiacie -- błędy w obliczeniach zmiennoprzecinkowych są naturalne i wręcz "wrodzone" w ten typ. Nie da się inaczej...

A właśnie że da się!

Generalnie zawsze powinno być tak:

x op y = z

op - dowolna operacja.

a w wersji numerycznej jest to obliczane tak:

fl(fl(x) op fl(y)) = fl(z)

i ten warunek musi być zagwarantowany!

W szczególności:

fl(sqrt(4)) = fl(2) = 2; dokładnie, bo: 2 = fl(2)!

Weźcie uruchomcie sobie ulubiony język/interpreter/kompilator i sprawdźcie:

>>> 0.1 + 0.2 == 0.3
False

(u mnie to akurat Python 3.4.2, ale w gcc 6.3.0 jest to samo).

Ktoś kiedyś powiedział, że komputery nie nadają się do obliczeń... :)

Widocznie Python też jest źle zaprogramowany - niezgodnie z regułami metod numerycznych.

1
wall napisał(a):

A właśnie że da się!

Generalnie zawsze powinno być tak:

x op y = z

op - dowolna operacja.

a w wersji numerycznej jest to obliczane tak:

fl(fl(x) op fl(y)) = fl(z)

i ten warunek musi być zagwarantowany!

Pleciesz, ten warunek nie da się zagwarantować...

Na przykład dla różnicy między liczbami, które dużo się od siebie różnią, wynik musi wyjść zero w arytmetyce zmiennopozycyjnej, ale przecież nie będzie to zgodne z Twoim równaniem, pomyśl...

0
koszalek-opalek napisał(a):
wall napisał(a):

A właśnie że da się!

Generalnie zawsze powinno być tak:

x op y = z

op - dowolna operacja.

a w wersji numerycznej jest to obliczane tak:

fl(fl(x) op fl(y)) = fl(z)

i ten warunek musi być zagwarantowany!

Pleciesz, ten warunek nie da się zagwarantować...

Na przykład dla różnicy między liczbami, które dużo się od siebie różnią, wynik musi wyjść zero w arytmetyce zmiennopozycyjnej, ale przecież nie będzie to zgodne z Twoim równaniem, pomyśl...

Cóż, tutaj akurat wall ma rację - fl(fl(x) op fl(y)) = fl(z) powinno zachodzić zawsze. Oczywiście, fl(0.1) != 0.1, i stąd 0.1 + 0.2 != 0.3. Natomiast wiadomo, iż fl(sqrt(fl(4))) = fl(sqrt(4)) = fl(2) = 2.

0
enedil napisał(a):
koszalek-opalek napisał(a):
wall napisał(a):

A właśnie że da się!

Generalnie zawsze powinno być tak:

x op y = z

op - dowolna operacja.

a w wersji numerycznej jest to obliczane tak:

fl(fl(x) op fl(y)) = fl(z)

i ten warunek musi być zagwarantowany!

Pleciesz, ten warunek nie da się zagwarantować...

Na przykład dla różnicy między liczbami, które dużo się od siebie różnią, wynik musi wyjść zero w arytmetyce zmiennopozycyjnej, ale przecież nie będzie to zgodne z Twoim równaniem, pomyśl...

Cóż, tutaj akurat wall ma rację - fl(fl(x) op fl(y)) = fl(z) powinno zachodzić zawsze. Oczywiście, fl(0.1) != 0.1, i stąd 0.1 + 0.2 != 0.3. Natomiast wiadomo, iż fl(sqrt(fl(4))) = fl(sqrt(4)) = fl(2) = 2.

Taka operacja ma być dokładna, co znaczy że: 0.1 + 0.2 == 0.3;

0.2 = 2 * 0.1,
zatem tu nie powinno być różnicy - na poziomie bitów, czyli 0.3 wygląda dokładnie tak samo jak 0.1+0.2.

zresztą można sobie to łatwo obliczyć, np. na arytmetyce z precyzją 2 cyfr - no i co wyjdzie?
A komputery właśnie tak to robią.

1
wall napisał(a):
enedil napisał(a):
koszalek-opalek napisał(a):
wall napisał(a):

A właśnie że da się!

Generalnie zawsze powinno być tak:

x op y = z

op - dowolna operacja.

a w wersji numerycznej jest to obliczane tak:

fl(fl(x) op fl(y)) = fl(z)

i ten warunek musi być zagwarantowany!

Pleciesz, ten warunek nie da się zagwarantować...

Na przykład dla różnicy między liczbami, które dużo się od siebie różnią, wynik musi wyjść zero w arytmetyce zmiennopozycyjnej, ale przecież nie będzie to zgodne z Twoim równaniem, pomyśl...

Cóż, tutaj akurat wall ma rację - fl(fl(x) op fl(y)) = fl(z) powinno zachodzić zawsze. Oczywiście, fl(0.1) != 0.1, i stąd 0.1 + 0.2 != 0.3. Natomiast wiadomo, iż fl(sqrt(fl(4))) = fl(sqrt(4)) = fl(2) = 2.

Taka operacja ma być dokładna, co znaczy że: 0.1 + 0.2 == 0.3;

0.2 = 2 * 0.1,
zatem tu nie powinno być różnicy - na poziomie bitów, czyli 0.3 wygląda dokładnie tak samo jak 0.1+0.2.

zresztą można sobie to łatwo obliczyć, np. na arytmetyce z precyzją 2 cyfr - no i co wyjdzie?
A komputery właśnie tak to robią.

Sorki, wall, ale widzę, że nie masz pojęcia o arytmetyce zmiennoprzecinkowej... Nie bierz tego osobiście, ale...

Na poziomie bitów 0.3 nie będzie wyglądać dokładnie tak samo jak 0.1+0.2. Z różnych powodów. Głównym jest to, że wszystkie rzeczone trzy liczby mają nieskończone rozwinięcie dwójkowe, więc nie mogą być przechowane dokładnie w dwójkowej reprezentacji zmiennoprzecinkowej.

Możesz podać jakieś źródło, że, jak napisałeś "Taka operacja ma być dokładna, co znaczy że: 0.1 + 0.2 == 0.3"? Bo ja nie znam takowego i -- całkiem poważnie piszę -- chętnie bym się dowiedział, że się mylę... :)

2

Liczby z 0.1 + 0.2 == 0.3 mają dokładną reprezentację stałopozycyjną, ale nie zmiennoprzecinkową.
Cała dziedzina "obliczenia numeryczne" opiera się na znajomości tego typu zagadnień.
Jakby na komputerach dało się obliczać wszystko tak jak na lekcji matematyki na tablicy, to niepotrzebna byłaby numeryka.

Zmienne stałopozycyjne używane są w bankowości i w... demach na starszych komputerach.

W celu zgłębienia tematu polecam sprawdzić jak jest zakodowana liczba zmienno-przecinkowa:
https://pl.wikipedia.org/wiki/IEEE_754
https://pl.wikipedia.org/wiki/Liczba_zmiennoprzecinkowa

A potem spróbować przedstawić w tym zapisie samemu wartość 0.3.

Pomocne może być to: https://www.h-schmidt.net/FloatConverter/IEEE754.html

0

Twierdzę że taka operacja będzie podawać poprawny wynik.

float x = 0.1, y = 0.2, z = 0.3, s = x+y;

if( s == z ) print 'równe'; // to wyjdzie!
else print 'różne'.

0

Wystarczy sprawdzić różnicę:

0.1+0.2 - 0.3 = ?

Gdyby tu 0.1+0.2 było różne od 0.3, wówczas wynik powinien być niezerowy, coś w stylu 2.5334343e-16, w przypadku obliczeń na double.

Nawet te spartaczone kalkulatory z Windows produkują tu 0.

0
wall napisał(a):

Wystarczy sprawdzić różnicę:

0.1+0.2 - 0.3 = ?

Gdyby tu 0.1+0.2 było różne od 0.3, wówczas wynik powinien być niezerowy, coś w stylu 2.5334343e-16, w przypadku obliczeń na double.

Nawet te spartaczone kalkulatory z Windows produkują tu 0.

A4 = 164, zatem to byłaby ujemna, więc odejmujemy 128, zostaje 36;
bias 127, czyli 36 - 127 = -91;

czyli to jest: - 2^-91, co jest raczej dobrze widoczne i niezerowe na poziomie float: -4.e-28,
byłoby możliwe np. takie coś:
1/x = ... oblicz to.

0
wall napisał(a):

Twierdzę że taka operacja będzie podawać poprawny wynik.

float x = 0.1, y = 0.2, z = 0.3, s = x+y;

if( s == z ) print 'równe'; // to wyjdzie!
else print 'różne'.

Zamiast pisać co powinno wyjść, to sprawdź... :)

wall napisał(a):

Wystarczy sprawdzić różnicę:

0.1+0.2 - 0.3 = ?

Gdyby tu 0.1+0.2 było różne od 0.3, wówczas wynik powinien być niezerowy, coś w stylu 2.5334343e-16, w przypadku obliczeń na double.

Nawet te spartaczone kalkulatory z Windows produkują tu 0.

Kalkulatory produkują zero, bo zaokrąglają do iluś miejsc po przecinku.

Weź napisz w czymkolwiek (C++, Java, Python itd.) programy, które robią zaproponowane przez Ciebie testy, zobaczysz co wychodzi...

Twój przykłąd z float daje akurat równość, natomiast z double:

#include <iostream>

int main() {
    using namespace std;

    cout.setf(ios::scientific);
    cout.precision(30);

    double x = 0.1, y = 0.2, z = 0.3, s = x+y, r = s-z;
    if(s == z) {
        cout << "równe\n";
    } else {
        cout << "różne\n";
    }

    cout << x << endl;
    cout << y << endl;
    cout << z << endl;
    cout << s << endl;
    cout << r << endl;
}

daje:

różne
1.000000000000000055511151231258e-01
2.000000000000000111022302462516e-01
2.999999999999999888977697537484e-01
3.000000000000000444089209850063e-01
5.551115123125782702118158340454e-17

Nie jest natomiast problemem znaleźć liczby, dla których równości już nie ma dla float, bo dla:

#include <iostream>

int main() {
    using namespace std;

    cout.setf(ios::scientific);
    cout.precision(30);

    float x = 0.0001, y = 0.0002, z = 0.0003, s = x+y, r = s-z;
    if(s == z) {
        cout << "równe\n";
    } else {
        cout << "różne\n";
    }

    cout << x << endl;
    cout << y << endl;
    cout << z << endl;
    cout << s << endl;
    cout << r << endl;
}

dostajemy już:

różne
9.999999747378751635551452636719e-05
1.999999949475750327110290527344e-04
3.000000142492353916168212890625e-04
2.999999851454049348831176757812e-04
-2.910383045673370361328125000000e-11

PS. Mam wrażenie, że wall to jakiś wytrawny troll (bo czemuż pisze bez rejestracji), albo też młody gniewny, który nie wie jak działają komputery i chciałby, żeby wszystko było idealne... :)

0

Kalkulatory produkują zero, bo oblicza to poprawnie,
i nie 'zaokrąglając do iluś miejsc po przecinku', bo wtedy otrzymałbyś wynik w stylu: 4.6565e-300, a zero!

Weź napisz w czymkolwiek (C++, Java, Python itd.) programy, które robią zaproponowane przez Ciebie testy, zobaczysz co wychodzi...
Twój przykłąd z float daje akurat równość, natomiast z double:

Z double tak samo jest 0 - dokładnie.
Pewnie kompilatorek miesza obliczenia z różną precyzją - single z double i jeszcze z long double na FPU, no i stąd te bzdury potem.

Przypominam jeszcze raz:
obliczenia na komputerach są wykonywane dokładnie tak samo, jak to robimy ze skończoną liczbą cyfr precyzji!

1+2 = 3 - jedna cyfra precyzji!
0.1+0.2 = 0.3 - też jedna cyfra precyzji tu wystarczy!

1.21*1.22 = 1.4762 = 1.48 - dla 3 cyfr precyzji...
itd.

0

No to spójrz na taki kod:

double d = 0;
for (i = 0; i < 10; ++i) {
    d += (double)0.1;
}
printf("%d\n", d == (double)1);

Zgodnie z oczekiwaniem, zwraca zero.

Dzieje się tak, gdyż 0.1, to inaczej 1.(9) * 16^(-4) (9 jest w okresie). Aby liczbę tę zapisać jako float, trzeba ją gdzieś uciąć. Niech błąd na każdej takiej liczbie wyniesie b, wówczas błąd całkowity to 10b, z pewnością nie 0.

0

To się robi zabawne... :)

wall napisał(a):

Kalkulatory produkują zero, bo oblicza to poprawnie,
i nie 'zaokrąglając do iluś miejsc po przecinku', bo wtedy otrzymałbyś wynik w stylu: 4.6565e-300, a zero!

Weź napisz w czymkolwiek (C++, Java, Python itd.) programy, które robią zaproponowane przez Ciebie testy, zobaczysz co wychodzi...
Twój przykłąd z float daje akurat równość, natomiast z double:

Z double tak samo jest 0 - dokładnie.
Pewnie kompilatorek miesza obliczenia z różną precyzją - single z double i jeszcze z long double na FPU, no i stąd te bzdury potem.

Sprawdziłeś? Podaj wersję dla której wychodzą Ci dokładne wyniki w moich dwóch programach z mojego poprzedniego postu...

No i poza tym, co wyszło Ci z mojego przykładu z float?

Przypominam jeszcze raz:
obliczenia na komputerach są wykonywane dokładnie tak samo, jak to robimy ze skończoną liczbą cyfr precyzji!

Niby tak, ale w systemie dwójkowym.

1+2 = 3 - jedna cyfra precyzji!

Tak, tu wystarczy jedna cyfra precyzji.

0.1+0.2 = 0.3 - też jedna cyfra precyzji tu wystarczy!

To już nie wystarczy jedna cyfra precyzji, bo dwójkowo wszystkie te liczby mają nieskońćzone rozwinięcie, więc w żadnej skońćzonej przycji NIE DADZĄ się przedstawić dokładnie.

Doucz się, proszę...

0
enedil napisał(a):

No to spójrz na taki kod:

double d = 0;
for (i = 0; i < 10; ++i) {
    d += (double)0.1;
}
printf("%d\n", d == (double)1);

Zgodnie z oczekiwaniem, zwraca zero.

Suma wielu liczb może już produkować błędy większe od eps - maszynowego.

Dzieje się tak, gdyż 0.1, to inaczej 1.(9) * 16^(-4) (9 jest w okresie). Aby liczbę tę zapisać jako float, trzeba ją gdzieś uciąć. Niech błąd na każdej takiej liczbie wyniesie b, wówczas błąd całkowity to 10b, z pewnością nie 0.

Nie ma takiego zapisu liczb.
W double 0.1 wygląda tak: 2^-4 * (1 + x)
gdzie to x to ~0.6 zapisane binarne na długości 52 bitów.

1.6 = 1 + 0.1001100110011... b = 1 + 1/2 + (1/16 + 1/32) + (1/256 + 1/512) + ...

0

Finalizując tę farsę powiem tyle:
już nie dziwię się wcale, że ten kalkulatorek z Windows rypie te obliczenia, bo on... za dobrze to oblicza!
Wedle waszych kretyńskich wyobrażeń on powinien tak liczyć:

1 + 1 - 2 = 0.000000000001

0
wall napisał(a):

W double 0.1 wygląda tak: 2^-4 * (1 + x)
gdzie to x to ~0.6 zapisane binarne na długości 52 bitów.

1.6 = 1 + 0.1001100110011... b = 1 + 1/2 + (1/16 + 1/32) + (1/256 + 1/512) + ...

A, więc w końcu zgadzasz się z nami, że 0.1 nie da się zapisać dwójkowo na skończonej liczbie bitów? :)

Czyli sam sobie w końcu odpowiedziałeś na trapiące Cię problemy...

0

Pewnie kompilatorek miesza obliczenia z różną precyzją - single z double i jeszcze z long double na FPU, no i stąd te bzdury potem.

Sprawdziłeś? Podaj wersję dla której wychodzą Ci dokładne wyniki w moich dwóch programach z mojego poprzedniego postu...

No i poza tym, co wyszło Ci z mojego przykładu z float?

Mi wychodzi dobrze i dla dowolnych liczb:

a + b - (a+b) = 0.

Przypominam jeszcze raz:
obliczenia na komputerach są wykonywane dokładnie tak samo, jak to robimy ze skończoną liczbą cyfr precyzji!

Niby tak, ale w systemie dwójkowym.

Binarne to zwyczajne liczby o bazie 2, czyli najprostsze w obliczeniach.

Przykładowo:

1/3 + 2/3 = 3/3 = 1

i teraz wedle tych waszych naiwnych pomysłów powinno być tak:
0.9999999999999999999

zgadza się?
Bzdura!
Takie coś 0.99999999 będzie zawsze zaokrąglone do równo 1.000, bowiem jedna cyfra powyżej precyzji będzie na pewno > 5 (w binarnych =1) !

0
koszalek-opalek napisał(a):
wall napisał(a):

W double 0.1 wygląda tak: 2^-4 * (1 + x)
gdzie to x to ~0.6 zapisane binarne na długości 52 bitów.

1.6 = 1 + 0.1001100110011... b = 1 + 1/2 + (1/16 + 1/32) + (1/256 + 1/512) + ...

A, więc w końcu zgadzasz się z nami, że 0.1 nie da się zapisać dwójkowo na skończonej liczbie bitów? :)

Czyli sam sobie w końcu odpowiedziałeś na trapiące Cię problemy...

To nic szkodzi w arytmetyce na floatach, bowiem:

fl(fl(a) + fl(b)) = fl(a+b)

to znaczy że liczba (a+b) będzie tu dokładnie tak samo reprezentowana, jak suma tych dwóch - dowolnych, które w poprawnej arytmetyce dają w sumie.. tęże sumę! /:

0

Wy faktycznie nie macie pojęcia jak komputer oblicza.

Nawet takie coś jest tu dokładnie liczone:
arctan(1) - pi/4 = 0

i dokładnie zero, nie żadne 1.5656e-65, co wam się tu pewnie roi w tępych główkach.

Programiści, którzy o podstawach arytmetyki nie słyszeli - dobry skecz... ale i fakt.

0

Sorry ale:
0.1 + 0.2 - 0.3 = 0 - dokładnie i niezależnie od typu floatów - ich precyzji!

Dowolny kalkulator to wykaże i dla dowolnych liczb, które spełniają ten warunek: a+b = c, ponieważ:

fl(fl(a) + fl(b)) = fl(c), taka jest zasada w arytmetyce na floatach, czyli na liczbach o skończonej i ustalonej precyzji.

0

Kilka fantastycznych opinii nieuków:

https://www.quora.com/Why-hasn%E2%80%99t-Microsoft-ever-fixed-the-square-root-bug-in-Windows-Calculator

Is this an error?
No, the calculator programmer was asked to develop a program that was accurate to 32 digits of precision.
The returned answer is accurate to that many significant digits
The calculator did give us a precise answer, 2.

hahaha!

0

Jako że dyskusja nie zmierza w żadną stronę i nasz anonimowy @wall najwyraźniej nie zamierza pojąć, że plecie bzdury, zamykam wątek.

Liczby zmiennoprzecinkowe, zgodnie z IEEE 754, są nieprecyzyjne, przez co przykładowo 0.1 + 0.2 != 0.3. Nie ma w tym żadnej magii ani niedeterministyczności, nie ma potrzeby oglądania filmów z żółtymi napisami, aby to sprawdzić.

1 użytkowników online, w tym zalogowanych: 0, gości: 1