2011-12-07 28 views
13

Soy un desarrollador Objective-C con poca experiencia en C/C++ (y cero capacitación), y encontré algo extraño hoy con valores numéricos codificados.Problema Int to Double casting

Estoy seguro de que es una simple pregunta/estúpida, pero por favor alguien puede explicar por qué esto funciona:

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 

Y esto también funciona (número de nota de segundos ha cambiado):

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 

Pero esto se ejecuta inmediatamente:

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 

Sin embargo, utilizando en su lugar 4.04 de lo fija:

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 

¿Por qué 1 y 2 adecuadamente fundido al valor doble relevante, pero los números más grandes (he probado 3 y 4) parecen estar representado como 0?

Estoy compilando con Xcode 4.2, configurado para usar LLVM 3.0.

EDIT:

dispatch_time_t se define como:

typedef uint64_t dispatch_time_t; 

Y dispatch_time es:

dispatch_time_t dispatch_time(dispatch_time_t when, int64_t delta); 

Y NSEC_PER_SEC es:

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

¿Cuál es el parámetro de dispatch_time? – Pubby

+0

Gracias @Pubby, he actualizado la pregunta. –

+0

que parece muy extraño que 1,2 trabajo y 3,4 no ... Lo comprobaría dos veces, pero sí se observan instancias donde los resultados se evaluarán a 0f. –

Respuesta

25

Hay 1,000,000,000 de nanosegundos en un segundo, así que supongo que NSEC_PER_SEC se define como 1000000000.

  • 4 es de tipo int
  • 4.0 es de tipo double

Ahora suponiendo que un int contiene 32 bits, el rango de un int sería [-2,147,483,648 to 2,147,483,647]

4000000000 > 2147483647, por lo tanto causará que el int se desborde, lo que está causando que el valor se vea t a 0.

EDIT: Probablemente podría haber redactado mejor la afirmación anterior. El desbordamiento podría ocasionar que int (suponiendo que tenga un tamaño de 32 bits, como se indicó anteriormente) iguale el valor -294967296, y dispatch_time trataría cualquier valor <= 0 como 0 segundos. De ahí viene el "0" de arriba.

Una variable double puede contener valores mayores que int, y es capaz de almacenar una aproximación del valor 4000000000.

+0

Gracias por una respuesta perfectamente clara. :) –

+1

Exactamente perfecto. +1. –

+1

Cuando el cálculo se desborda, se ajustará, no a cero. El valor aquí probablemente sea <0, y el envío probablemente lo trate como "hacerlo de inmediato". –

7

Los dos primeros trabajos, porque 1 * 10^9 y 2 * 10^9 caben en un int firmado de 32 bits. Sin embargo, 4 * 10^9 no cabrán en un int firmado de 32 bits.

4.0 * 10^9 funciona porque el punto flotante puede representar ese valor.

espero que esto también funcionará:

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

No sé nada de Objective C, pero mi conjetura es que 4 * NSEC_PER_SEC es demasiado grande para un entero de 32 bits. Al usar 4.0, fuerza la multiplicación en aritmética de punto flotante y soluciona el problema.

actualización

Puede ser código de 64 bits, pero en algunos idiomas (y sé C# es uno) un numéricos predeterminados literales a un entero con signo de 32 bits a menos que se definan explícitamente de otra manera. Eso puede ser lo que está pasando aquí.

+0

Gracias, "NSEC" es nanosegundos, por lo que es un gran número. He actualizado mi pregunta con su definición. Por cierto, este es todo el código de 64 bits, aunque no sé si eso hace la diferencia. –

+0

Ver mi respuesta actualizada. –

+0

Sí, en UNIX de 32 bits o UNIX de 64 bits, int es 32-bits –