2016-07-25 62 views
9

Mam numer, który może być zerowy. Dzielę się przez tę liczbę, więc chcę sprawdzić, czy jest zero, aby zapobiec NaN i nieskończoności. Czy to możliwe, że nadal tworzę NaN/nieskończoność z powodu błędów zaokrąglania w obrębie podziału?Czy podział przez niezerowy nadal tworzy nan/infinity

double x; // might be zero 
double y; 

if(x != 0) return y/x; 

EDIT

Dzięki za odpowiedzi. Dodam wtedy kilka pytań.

1) zakładając, że ani x, ani y nie jest NaN/+ inf lub -inf, czy podział, który powoduje -inf/+ inf powoduje więcej cykli procesora lub jakiekolwiek inne niepożądane zachowanie? (Czy może się zawiesić?)

2) Czy istnieje sposób, aby zapobiec podziałowi w wyniku nieskończoności? Używanie przesunięć i tak dalej.

+0

mogą być nieskończoność lub nawet nan – EFenix

+2

Jeśli 'y' jest już NaN, wówczas wynik będzie również NaN. –

+2

Dodanie kolejnych pytań po tym, jak ktoś już opublikował odpowiedź (w tym przypadku 3) nie jest wspaniałe - sprawia, że ​​odpowiedzi te wyglądają na niekompletne, chociaż nie były, gdy zostały napisane. –

Odpowiedz

6

Podzielenie bardzo małej liczby na bardzo dużą liczbę lub pomnożenie dwóch bardzo dużych liczb może dać "nieskończoność". Dzielenie nieskończoności przez inną nieskończoność da NaN. Na przykład: (1E300/1E-300)/(1E300/1E-300) lub (1E300*1E300)/(1E300*1E300) oba będą dawały NaN.

9

Can dzielenie przez niezerową nadal tworzyć nan/nieskończoność

Tak.

Jeśli IEEE 754 następuje wówczas:

  • Jeżeli jedna operand NaN wynik będzie liczbą.
  • Jeśli licznik i licznik są nieskończoności, wynikiem jest NaN.
  • Jeśli licznik jest nieskończoność, wynikiem jest nieskończoność.
  • Jeśli podział za pomocą małego licznika (lub dużego licznika) zostanie przepełniony, wynik może być nieskończony, w zależności od bieżącego trybu zaokrąglania.

Zasady dotyczące innych oświadczeń mogą być różne.


2) ma sposób zapobiec devision prowadziły do ​​nieskończoności

Powinno się sposób zapobiegania, że:

#include <cfenv> 
#include <cassert> 
#include <cmath> 
#include <limits> 

// ... 

static_assert(std::numeric_limits<decltype(x)>::is_iec559, "Unknown floating point standard."); 
#pragma STDC FENV_ACCESS ON 
int failed = std::fesetround(FE_TOWARDZERO); 
assert(!failed); 
if(x != 0 && std::isfinite(x) && std::isfinite(y)) 
    return y/x; 
else 
    throw std::invalid_argument("informative message"); 

Niektóre kompilator może wymagać inne niż domyślne opcje umożliwiające pełną zgodność IEEE 754 (-frounding-math na GCC).

+0

"w zależności od bieżącego trybu zaokrąglania" Jest to krytyczne, patrz 'fegetround' /' fesetround'. Jeśli zaokrąglisz w stronę zera, nigdy nie dostaniesz inf, jeśli podzielisz się skończonym niezerowym. – sbabbi

+0

Czuję, że fesetround to nic, co należy nazwać funkcją wrażliwą na wydajność, prawda? –

+0

@ruhigbrauner być może nie. Możesz go przenieść poza gorące pętle. – user2079303

5

Tak, wystarczy spojrzeć na kod poniżej

#include <iostream> 
int main() 
{ 
    double x = 1, y = 2; 
    while (y != 0) { 
     std::cout << y << " " << x/y << std::endl; 
     y /= 2; 
    } 
} 

w pewnym momencie dostaniesz:

8.9003e-308 1.12356e+307 
4.45015e-308 2.24712e+307 
2.22507e-308 4.49423e+307 
1.11254e-308 8.98847e+307 
5.56268e-309 inf 
2.78134e-309 inf 
1.39067e-309 inf 
6.95336e-310 inf