2013-04-25 17 views
9

Mam sytuację, w której uzasadnione jest podzielenie przez 0,0 lub przez -0,0, gdzie oczekiwałbym odpowiednio + Inf i -Inf jako wyników. Wygląda na to, że Python lubi rzucić w obu przypadkach jeden rzutnik. Oczywiście, pomyślałem, że mogę po prostu zawinąć to z testem na 0,0. Jednak nie mogę znaleźć sposobu na rozróżnienie między +0,0 a -0,0. (FYI można łatwo uzyskać -0,0, wpisując go lub za pomocą typowych obliczeń, takich jak -1.0 * 0.0).Jak uzyskać podział Pythona o -0,0 i 0,0, aby uzyskać odpowiednio wartości "Inf i Inf"?

IEEE radzi sobie z tym bardzo ładnie, ale Python wydaje się usilnie starać się ukryć dobrze przemyślane zachowanie IEEE. W rzeczywistości fakt, że 0.0 == -0.0 jest rzeczywiście funkcją IEEE, więc zachowanie Pythona poważnie psuje rzeczy. Działa doskonale w językach C, Java, Tcl, a nawet JavaScript.

Sugestie?

Odpowiedz

11
from math import copysign 

def divide(numerator, denominator): 
    if denominator == 0.0: 
     return copysign(float('inf'), denominator) 
    return numerator/denominator 

>>> divide(1, -0.0) 
-inf 
>>> divide(1, 0) 
inf 
+1

+1, zdecydowanie czystsze niż moje rozwiązanie. – Blender

+1

Bardzo ładne - nie pomyślałoby o zrobieniu tego w ten sposób;) +1 –

8

Całkowicie zgadzam się z @Mark Ransom, chyba że użyłbym try zamiast:

def f(a, b): 
    try: 
     return a/b 
    except ZeroDivisionError: 
     return copysign(float('inf'), denominator) 

Powodem polecam jest to, że jeśli wykonują tę funkcję wiele razy, nie robić Trzeba tracić czas na każdą iterację sprawdzającą, czy wartość wynosi zero przed próbą podziału.

EDIT:

Mam porównaniu prędkość try porównaniu do if funkcję:

def g(a, b): 
    if b == 0: 
     return copysign(float('inf'), b) 
    else: 
     return a/b 

Oto testy:

s = time.time() 
[f(10, x) for x in xrange(-1000000, 1000000, 1)] 
print 'try:', time.time()-s 
s = time.time() 
[g(10, x) for x in xrange(-1000000, 1000000, 1)] 
print 'if:', time.time()-s 

Oto wynik:

try: 0.573683023453 
if: 0.610251903534 

Oznacza to, że metoda try jest szybsza, przynajmniej na moim komputerze.

+0

"Try ... except" jest w rzeczywistości wolniejsze niż "if". – Blender

+1

@Blender Właśnie zrobiłem kilka testów, które nie zgadzają się z tym; czy masz testy, które pokazują inaczej? – SethMMorton

+0

Nie mogę tego wkleić tutaj, ponieważ zajmie to 30 linii, ale [tutaj jest zrzut ekranu] (http://i.imgur.com/sqgbwJF.png). – Blender

2

Biblioteka zapewnia zmienną precyzję typu pływającego, a także pozwala kontrolować zachowanie wyjątku IEEE-754.

>>> import gmpy2 
>>> from gmpy2 import mpfr 
>>> mpfr(1)/mpfr(0) 
mpfr('inf') 
>>> mpfr(1)/mpfr(-0) 
mpfr('inf') 
>>> mpfr(1)/mpfr("-0") 
mpfr('-inf') 
>>> gmpy2.get_context().trap_divzero=True 
>>> mpfr(1)/mpfr(0) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
gmpy2.DivisionByZeroError: 'mpfr' division by zero in division 

Oświadczenie: Utrzymuję gmpy2.

+0

Dzięki. Sprawdzę gmpy2 pod kątem innego projektu, który skorzysta z arbitralnej precyzji.Mój obecny projekt wymaga najwyższej wydajności (wewnętrzne pętle) i nie wymaga arbitralnej precyzji. – Chuck

Powiązane problemy