Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

[C++] Obsługa przekraczania zakresu liczb całkowitych oraz zmiennoprzecinkowych

Ostatnio zmodyfikowano 2014-12-08 22:25
Autor Wiadomość
amilkwes
Temat założony przez niniejszego użytkownika
[C++] Obsługa przekraczania zakresu liczb całkowitych oraz zmiennoprzecinkowych
» 2014-12-02 19:48:25
W różnych w miejscach w kodzie występują operacje arytmetyczne, często nie są one niczym skrępowane i odpowiednio użyte mogą prowadzić do przekroczenia zakresu. Jak się bronić przed tego typu efektami? Jak wykrywać, że nastąpi przekroczenie zakresu? Ciekawi mnie to w kilku przypadkach:

1.
unsigned
, gdzie mamy zdefiniowane zachowanie przy przekroczeniu zakresu,
2.
signed
, gdzie nie mamy zdefiniowanego zachowania przy przekroczeniu zakresu,
3.
float
,
double
, czy bęziemy tutaj postępować jak w przypadku 1 lub 2?

Rozumiem, że można szacować jakie wartości może przyjąć dana zmienna, ale gdy robimy funkcje sumującą dane z vectora? Gdy zliczamy wystąpienia, dodajemy/odejmujemy wyniki pomiarów? Wtedy wartości mogą praktycznie dążyć do nieskończoności. Rozumiem też, że
std::numeric_limits
 daje możliwość poznania wartości granicznych, jednak dalej nie jestem w stanie sobie wyobrazić żywego przykadłu obsługi takich rzeczy.
P-121980
darko202
» 2014-12-05 09:01:28
to jest jak z kręceniem koła (zegarek) od 6 do 12 liczby ujemne od 12 do 6 dodatnie
jeśli liczba A =~3, B=~5   to A+B =~8 (na zegarze) a to już liczba ujemna
tak jest dla wszystkich typów liczbowych

dla liczb bez znaku 6 = 0, a (6 - jeden) to max liczba z zakresu

dzieje się tak ze względu na sposób zapisu liczby w systemie
http://www.lomilowka.pl/upload​/file/informatyka2​/binarna_ze_znakiem.pdf
P-122247
Monika90
» 2014-12-05 10:26:04
Ponieważ w przypadku wystąpienia przepełnienia zachowanie jest niezdefiniowane, to trzeba ewentualne przepełnienie wykrywać zanim się coś doda, odejmnie, czy pomnoży.
Na przykład:
C/C++
template < class T >
T add( T x, T y )
{
    using std::to_string;
    using limits = std::numeric_limits < T >;
    if(( x > 0 && y > 0 && x > limits::max() - y )
    ||( x < 0 && y < 0 && x < limits::min() - y ) )
         throw std::overflow_error( to_string( x ) + "+" + to_string( y ) );
   
    return x + y;
}

GCC 5.0 ma funkcje __builtin_add_overflow, __builtin_sub_overflow, __builtin_mul_overflow, które można tu wykorzystać.

W przypadku liczb zmiennoprzecinkowych wynikiem przepełnienia będzie + albo - nieskończoność oraz wyjątek zmiennoprzecinkowy, można to testować za pomocą isinf(sum) albo fetestexcept(FE_OVERFLOW).

Ogólnie radzenie sobie z przepełnieniem wymaga zrozumienia zakresu danych wejściowych, doboru odpowiednich typów danych i właściwych algorytmów. Np. std::accumulate radzi sobie z sumowaniem ciągu liczb w ten sposób, że pozwala użytkownikowi okreslić typ akumulatora, więc można sumować elementy std::vector<char>, a wynik mieć typu long long.
P-122249
amilkwes
Temat założony przez niniejszego użytkownika
» 2014-12-08 22:25:24
@Monika90 Dzięki, wszystko jasne.
P-122559
« 1 »
  Strona 1 z 1