[C++] Obsługa przekraczania zakresu liczb całkowitych oraz zmiennoprzecinkowych
Ostatnio zmodyfikowano 2014-12-08 22:25
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. |
|
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 |
|
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: 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. |
|
amilkwes Temat założony przez niniejszego użytkownika |
» 2014-12-08 22:25:24 @Monika90 Dzięki, wszystko jasne. |
|
« 1 » |