2011-12-07 18 views
13

Sono uno sviluppatore Objective-C con poca esperienza C/C++ (e formazione zero) e ho riscontrato qualcosa di strano oggi con valori numerici codificati.Problema di trasmissione da Int a Double

Sono sicuro che è un semplice/domanda stupida, ma qualcuno può spiegare il motivo per cui questo funziona:

NSDate *start = [NSDate date]; 
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC); 

dispatch_after(popTime, dispatch_get_main_queue(), ^{ 
    NSLog(@"seconds: %f", [start timeIntervalSinceNow]); 
}); 
// output: seconds: -1.0001 

E questo funziona anche (numero di nota di secondi è cambiato):

NSDate *start = [NSDate date]; 
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC); 

dispatch_after(popTime, dispatch_get_main_queue(), ^{ 
    NSLog(@"seconds: %f", [start timeIntervalSinceNow]); 
}); 
// output: seconds: -2.0001 

Ma questo viene eseguito immediatamente:

NSDate *start = [NSDate date]; 
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 4 * NSEC_PER_SEC); 

dispatch_after(popTime, dispatch_get_main_queue(), ^{ 
    NSLog(@"seconds: %f", [start timeIntervalSinceNow]); 
}); 
// output: seconds: -0.0001 

Tuttavia, utilizzando invece 4.0 di 4 lo fissa:

NSDate *start = [NSDate date]; 
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 4.0 * NSEC_PER_SEC); 

dispatch_after(popTime, dispatch_get_main_queue(), ^{ 
    NSLog(@"seconds: %f", [start timeIntervalSinceNow]); 
}); 
// output: seconds: -4.0001 

Perché 1 e 2 correttamente espressi al valore doppio rilevante, ma i numeri più grandi (I testate 3 e 4) sembrano essere rappresentate come 0?

Sto compilando con Xcode 4.2, configurato per utilizzare LLVM 3.0.

EDIT:

dispatch_time_t è definito come:

typedef uint64_t dispatch_time_t; 

E dispatch_time è:

dispatch_time_t dispatch_time(dispatch_time_t when, int64_t delta); 

E NSEC_PER_SEC è:

#define NSEC_PER_SEC 1000000000 /* nanoseconds per second */ 
+0

Che cos'è il parametro dispatch_time? – Pubby

+0

Grazie a @Pubby, ho aggiornato la domanda. –

+0

che sembra molto strano che 1,2 lavoro e 3,4 non ... Lo controllerò due volte, ma sicuramente vedrai i casi in cui i valori saranno valutati a 0f. –

risposta

25

Ci sono 1.000.000.000 di nanosecondi in un secondo, quindi presumo che lo NSEC_PER_SEC sia definito come 1000000000.

  • 4 è di tipo int
  • 4.0 è di tipo double

Ora supponendo che un int contiene 32 bit, la gamma di un int sarebbe [-2,147,483,648 to 2,147,483,647]

4000000000 > 2147483647, pertanto causerà l'overflow dello int, il che sta causando il valore t a 0.

MODIFICA: Probabilmente avrei potuto formulare meglio l'affermazione precedente. L'overflow potrebbe causare int (supponendo che abbia una dimensione di 32 bit, come indicato sopra) per uguagliare il valore -294967296 e dispatch_time tratterebbe qualsiasi valore <= 0 come 0 secondi. Ecco da dove proviene lo "0" sopra.

Una variabile double può contenere valori superiori a int ed è in grado di memorizzare un'approssimazione del valore 4000000000.

+0

Grazie per una risposta perfettamente chiara. :) –

+1

Esattamente spot on. +1. –

+1

Quando il calcolo trabocca, ti avvolgi, non a zero. Il valore qui sarà probabilmente <0 e la spedizione probabilmente lo tratta come 'fallo immediatamente'. –

7

I primi due lavoro perché 1 * 10^9 e 2 * 10^9 si adattano a un int firmato a 32 bit. Tuttavia, 4 * 10^9 non si adatta a un int firmato a 32 bit.

4.0 * 10^9 funziona perché il punto mobile può rappresentare quel valore.

Mi aspetto che questo funzionerà anche:

dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, ((int64_t)4) * NSEC_PER_SEC); 
2

Non so niente di Objective C, ma la mia ipotesi è che 4 * NSEC_PER_SEC è troppo grande per un intero a 32 bit. Usando 4.0 si forza la moltiplicazione in aritmetica in virgola mobile e si aggira il problema.

Aggiornamento

Può essere il codice a 64 bit, ma in alcune lingue (e so C# è uno) un numerici predefiniti letterale ad un numero intero con segno a 32 bit a meno che non si definisce esplicitamente il contrario. Potrebbe essere quello che sta succedendo qui.

+0

Grazie, "NSEC" è in nanosecondi, quindi è un numero grande. Ho aggiornato la mia domanda con la sua definizione. A proposito, questo è tutto il codice a 64 bit, anche se non so se questo faccia la differenza. –

+0

Vedere la mia risposta aggiornata. –

+0

Sì, su UNIX a 32 bit o UNIX a 64 bit, int è a 32 bit –

Problemi correlati