2010-08-27 11 views
10

Dire che ho due float Python a e b, c'è un modo semplice per scoprire quanti numeri reali rappresentabili sono tra i due nella rappresentazione IEEE-754 (o qualsiasi rappresentazione utilizzata dalla macchina utilizzata)?Numero di galleggianti tra due galleggianti

+1

Solo per curiosità, che cosa avete bisogno di questa informazione per? –

+0

Come intendete? Due galleggianti specifici o in generale? E vuoi essere in grado di farlo da Python o vuoi fare i calcoli manualmente? – terminus

+0

Voglio confrontare due numeri in virgola mobile per determinare se sono uguali a una precisione vicina ma non uguale alla precisione della rappresentazione. Sono interessato a farlo in Python. Vedi la funzione AlmostEqual2sComplement su http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm - So che posso farlo con cose come (ab)/a astrofrog

risposta

10

io don'tknow quello che verrà utilizzato per questo - ma, se entrambi i carri hanno lo stesso esponente, dovrebbe essere possibile. Poiché l'esponente viene mantenuto sui bit di ordine elevato, il caricamento dei byte float (8 byte in questo caso) come numero intero e la sottrazione di uno da un altro dovrebbe fornire il numero desiderato. Io uso il modello struct per imballare i carri ad una rappresentazione binaria, e quindi decomprimere quelli come (C, 8 byte) lunghe interi:

>>> import struct 
>>> a = struct.pack("dd", 1.000000,1.000001) 
>>> b = struct.unpack("ll",a) 
>>> b[1] - b[0] 
4503599627 
>>> a = struct.pack("dd", 1.000000000,1.000000001) 
>>> b = struct.unpack("ll",a) 
>>> b[1] - b[0] 
4503600 
>>> 
+0

l'esponente non ha importanza, ma il segno lo fa. –

+3

+1; bella risposta. Tuttavia, non funzionerà su sistemi con C a 32 bit. Per sicurezza, usa "

+0

Per completare, si potrebbe anche ricordare che questa soluzione funziona solo con i formati IEEE 754. In pratica, non si tratta di una restrizione, anche se --- è molto difficile trovare Python in esecuzione su una piattaforma che utilizza doppi non IEEE 754. –

3

Per i numeri positivi b> a> 0, la risposta è circa:

(2**52) ** (log(b,2) - log(a,2)) 

Ci sono 52 bit della mantissa (oltre il implicita 1), moltiplicata per 2 elevato ad un esponente.

Quindi ci sono 2 ** 52 numeri nella gamma [1: 2) come nel range [1024: 2048)

+0

La teoria è buona, ma non funziona per me quando i numeri float sono troppo vicini. Probabilmente a causa del fatto che il calcolo del log introduce alcuni arrotondamenti. – jsbueno

12

per quanto ne so, carri IEEE754 hanno una proprietà interessante. Se si dispone di float f, quindi

(*(int*)&f + 1) 

in determinate condizioni, è il successivo numero a virgola mobile rappresentabile. Quindi per i galleggianti a e b

*(int*)&a - *(int*)&b 

Vi darà la quantità di numeri in virgola mobile tra quei numeri.

Vedere http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm per ulteriori informazioni.

+6

L'unico requisito è che abbiano lo stesso segno, e né Nan né inf. –

+0

Sembra che sia * la * risposta alla domanda, ma manca una parte: come si fa in Python? – Bolo

+0

Sebbene questo non risponda alla domanda per Python, questa è un'ottima risposta. Anche il mio libro di testo su "Metodi computazionali" concorda con questo. Qualcuno sa come convertire questo in Python? – Dragontamer5788

0

Guarderei la funzione frexp nel modulo matematico. L'esempio seguente estrae la mantissa e la converte in un numero intero. La differenza dovrebbe essere il numero di float tra i due valori.

>>> math.frexp(1.1234567890)[0] * 2**53 
5059599576307254.0 
>>> math.frexp(1.12345678901)[0] * 2**53 
5059599576352290.0 

Il seguente codice dovrebbe farlo:

import math 
import sys 

def delta(x,y): 
    '''Return the number of floats between x and y.''' 
    x = float(x) 
    y = float(y) 
    if x == y: 
     return 0 
    elif x < y: 
     return -delta(y,x) 
    else: 
     x_mant, x_exp = math.frexp(x) 
     y_mant, y_exp = math.frexp(y) 
     x_int = int(x_mant * 2**(sys.float_info.mant_dig + x_exp - y_exp)) 
     y_int = int(y_mant * 2**sys.float_info.mant_dig) 
     return x_int - y_int 

print(delta(1.123456789, 1.1234567889999)) 
450 
>>> 
Problemi correlati