2010-12-29 14 views
13

Stavo facendo alcuni calcoli di arrotondamento ed è successo su una domanda. Come posso esprimere la massima quantità inferiore a 1 per un determinato tipo di virgola mobile?Quantità massima in virgola mobile espressa inferiore a 1

Cioè, come scrivo/rappresento il valoretale che x < 1, x + y >= 1 per qualsiasi y > 0.

In frazioni questo sarebbe x = (q-1)/q dove q è il precisione del tipo. Ad esempio, se si contano in incrementi 1/999, quindi x = 998/999.

Per un determinato tipo (float, double, long double), come è possibile esprimere il valore x nel codice?


Mi chiedo anche se tale valore è presente in realtà per tutti i valori di y. Cioè, dato che l'esponente y's diventa più piccolo forse la relazione non regge più. Quindi è accettabile anche una risposta con qualche limite di intervallo su . (Il valore di x Voglio ancora esiste, la relazione potrebbe non proprio esprimerlo correttamente.)

+0

Stai cercando una formula? Una costante? Un algoritmo per trovarlo? – Maxpm

+0

Una costante sarebbe preferibile, ma una funzione sarebbe anche accettabile. –

+0

dai un'occhiata a dlamch over netlib –

risposta

12

C99 definisce la funzione nextafter(). Usalo come

#include <math.h> 
double under_one = nextafter(1, 0); 
+0

Cosa succede se '(float) 1' è già poco meno di 1? –

+0

@Chris '1' è rappresentato precisamente in binario, quindi usarlo come ho scritto ti darà il massimo possibile" under 1 "doppio valore – qrdl

+0

Sì, sembra essere esattamente quello che voglio. Esiste un modo per esprimere questo valore come costante? Cioè, se desidero usarlo come parametro predefinito? –

2

C'è un modo per acquisire la quantità più bassa che viene aggiunta a 1 produrrebbe quantità minima espressa maggiore di 1. Questo è std::numeric_limits<type>::epsilon() . Se si prova che questa quantità è uguale a quello che si cerca, che è quello che vuoi:

modello statico _TP std :: numeric_limits < _TP> :: epsilon() throw() [in linea, statico] I epsilon macchina: la differenza tra 1 e il valore minimo maggiore di 1 che è rappresentabile.

+0

È garantito che '1 - epsilon + epsilon == 1'? –

+0

La risposta è probabilmente "no". Ho sperimentato con la funzione nextafter(), cercando di ottenere epsilon da 1.0 a 0.0 e verso 2.0 - i risultati sono diversi. Epsilon verso 2.0 è esattamente due volte più grande di verso 0.0 - probabilmente perché quest'ultimo è espresso usando i numeri denormalizzati, che hanno 1 bit in più per la precisione. – mbaitoff

+0

Per il punto in virgola mobile, 1-epsilon sarà troppo grande. Esemplare con un formato FP con 3 cifre binarie: il numero successivo dopo 1.00 è 1,01, quindi epsilon è 0,01, mentre il numero prima di 1.00 è 0,111. – AProgrammer

4

altri Altouht hanno ragione che una maggiore valore inferiore 1 è 1-FLT_EPSILON, in virgola mobile che non può soddisfare condizioni x < 1, x + y >= 1 per qualsiasi y > 0, a meno che non si sta utilizzando arrotondamenti.

Il motivo è che la distanza tra 1 e precedente ad esso (che è FLT_EPSILON ~ 1,2E-7) è molto maggiore del numero minimo rappresentabile positivo FLT_MIN, che è ~ 1,2E-38. Quindi esiste una classe di numeri (FLT_MIN ... FLT_EPSILON/2 in caso di arrotondamento al più vicino, che è l'impostazione predefinita per la maggior parte dei sistemi) per cui (1-FLT_EPSILON)+y == (1-FLT_EPSILON) < 1.

+0

Anche questo è utile. Riguarda la mia preoccupazione sul fatto che un tale numero sia possibile. –

+0

Questo non implica che epsilon da 1.0 a 0.0 sia FLT_EPSILON/2? – mbaitoff

+0

Non sono sicuro che sia così, ma sembra esserlo. Potrei sbagliarmi nei dettagli. L'intervallo può essere FLT_MIN ... FLT_EPSILON/4, non/2, poiché è la metà del epsilon effettivo, ma esiste. – Vovanium

1

La rappresentazione in virgola mobile IEEE 754 ha la proprietà che per i numeri che sono positivi e non NaN l'ordine è uguale all'ordine sui modelli di bit visualizzati come numeri interi.

Quindi è possibile reinterpretare il modello di bit del numero in virgola mobile 1.0 come numero intero, decrementare tale numero intero e quindi reinterpretarlo nuovamente come numero in virgola mobile, per ottenere il numero in virgola mobile appena inferiore a uno.

1

In base allo standard IEEE 754, la precisione singola (32 bit) 1.0 ha la rappresentazione 0x3F800000.Possiamo scrivere questo in binario come 0 01111111 (1) 00000000000000000000000, che significa:

sign = 0 
biased exponent = 01111111 = 0x7F, so exponent = -23 (decimal) 
mantissa = 0x800000 (the (1) in parentheses is the implied msb) 

Quindi il valore è 0x800000 * 2^-23, che è 1,0. Il prossimo numero più basso in singola precisione è

0 01111110 (1)11111111111111111111111 

o 0x3F7FFFFF, o 0xFFFFFF * 2^-24, che è di circa 0,99,999994 millions.

+0

AFAIK, rappresentazione IEEE-754 implica un MSB nascosto sempre uguale a 1 (a meno che non sia un numero denormale). Pertanto, la quantità più elevata al di sotto di 1,0 sarebbe rappresentata come tutto-uno (1) mantissa e (-1) esponente. L'MSB di quel numero sarebbe implicito (1), quindi la mantissa riceve effettivamente un altro bit. Ecco perché epsilon verso 0.0 è 2 volte più fine di epsilon verso 2.0. – mbaitoff

1

La funzione nextafter() funziona bene @qrdl

#include <math.h> 
// find next double from 1.0 working towards 0.0 
double before_1 = nextafter(1.0, 0.0); 

ancora farlo al valore di fase di compilazione come commentato da @OP in un modo altamente portatile:

#include <float.h> 
double before_1 = 1.0 - DBL_EPSILON/FLT_RADIX; 

DBL_EPSILON è la differenza assoluta tra 1,0 e il prossimo maggioredouble.

FLT_RADIX è la radice (base) del sistema a virgola mobile. Spesso 2. Sono stati usati valori come 16 e 10.

Problemi correlati