Ver la versión completa : Duda con un programa de C que me está volviendo loco
¿Por qué en este código senderID1 y senderID2 no valen lo mismo?
var1 = channel.Service_ID;
var2 = channel.Audio_PID*powf(2, 16);
var3 = (channel.TunerType + 1)*powf(2, 29);
var4 = channel.TransportStream_ID*powf(2, 32);
var5 = ((channel.TunerType-1)*500*10)*powf(2, 48);
var6 = (channel.Flags & (1 << 3)?1:2)*powf(2, 61);
senderID1 = var1 + var2 + var3 + var4 + var5 + var6;
senderID2 = channel.Service_ID + channel.Audio_PID*powf(2, 16) + (channel.TunerType + 1)*powf(2, 29) + channel.TransportStream_ID*powf(2, 32) + ((channel.TunerType-1)*500*10)*powf(2, 48) + (channel.Flags & (1 << 3)?1:2)*powf(2, 61);
El resultado es éste:
senderID1 = 2305847528600401057
senderID2 = 2305847528600400896
y el resultado correcto es el de senderID1. ¿Será cosa del Visual Studio?
¿Sera cosa de que las variables se actualizan entre el calculo de senderID1 y senderID2?
Tambien se me ocurre que alguno de los valores que se asignan a las variables sobrepasen el valor de las mismas y se pierda información, o que las variables sean enteras y el valor que se calcula para las mismas tenga cifras decimales que se desechan y que por eso el calculo directo difiera del precalculado.
No. Era un problema de casting que con tanto long long se me va la pinza:
senderID2 = long long(channel.Service_ID) + long long(channel.Audio_PID*powf(2, 16)) + long long((channel.TunerType + 1)*powf(2, 29)) + long long(channel.TransportStream_ID*powf(2, 32)) + long long(((channel.TunerType-1)*500*10)*powf(2, 48)) + long long((channel.Flags & (1 << 3)?1:2)*powf(2, 61));
senderID1 = 2305847528600401057
senderID2 = 2305847528600401057
chipan, no vi antes tu edición pero el problema es que channel.Service_ID es un entero y el resto de las operaciones son long long, así que la solución menos guarra es:
senderID2 = channel.Service_ID + long long(channel.Audio_PID*powf(2, 16) + (channel.TunerType + 1)*powf(2, 29) + channel.TransportStream_ID*powf(2, 32) + ((channel.TunerType-1)*500*10)*powf(2, 48) + (channel.Flags & (1 << 3)?1:2)*powf(2, 61));
No. Era un problema de casting que con tanto long long se me va la pinza:
senderID2 = long long(channel.Service_ID) + long long(channel.Audio_PID*powf(2, 16)) + long long((channel.TunerType + 1)*powf(2, 29)) + long long(channel.TransportStream_ID*powf(2, 32)) + long long(((channel.TunerType-1)*500*10)*powf(2, 48)) + long long((channel.Flags & (1 << 3)?1:2)*powf(2, 61));
senderID1 = 2305847528600401057
senderID2 = 2305847528600401057
chipan, no vi antes tu edición pero el problema es que channel.Service_ID es un entero y el resto de las operaciones son long long, así que la solución menos guarra es:
senderID2 = channel.Service_ID + long long(channel.Audio_PID*powf(2, 16) + (channel.TunerType + 1)*powf(2, 29) + channel.TransportStream_ID*powf(2, 32) + ((channel.TunerType-1)*500*10)*powf(2, 48) + (channel.Flags & (1 << 3)?1:2)*powf(2, 61));
Bueno, entonces no iba desencaminado XD
Es que usas potencias muy grandes, es normal que tengas que usar long long. Por cierto, en C el casting se hace poniendo el tipo entre paréntesis así, no sea que te coja otra cosa: (long long)(expresión). También podrias usar el tipo int64_t, que es estándar. Otra cosa importante, haz el casting a los operadores directamente, ya que si haces (long long) (a * b), no es lo mismo que (long long) a * b, ya que en el primer caso (a*b) se te puede desbordar.
También si los números que estás operando son enteros, puedes hacer N<<M para multiplicar por potencias de 2. Por ejemplo: N<<3 es lo mismo que N * powf(2, 3). Queda más limpio cuando se manejan bits, además de que al pasarlo a double puedes perder precisión. Ojo, esto sólo si son enteros los operadores.
Es que usas potencias muy grandes, es normal que tengas que usar long long. Por cierto, en C el casting se hace poniendo el tipo entre paréntesis así, no sea que te coja otra cosa: (long long)(expresión). También podrias usar el tipo int64_t, que es estándar. Otra cosa importante, haz el casting a los operadores directamente, ya que si haces (long long) (a * b), no es lo mismo que (long long) a * b, ya que en el primer caso (a*b) se te puede desbordar.
También si los números que estás operando son enteros, puedes hacer N<<M para multiplicar por potencias de 2. Por ejemplo: N<<3 es lo mismo que N * powf(2, 3). Queda más limpio cuando se manejan bits, además de que al pasarlo a double puedes perder precisión. Ojo, esto sólo si son enteros los operadores.
¡Gracias por los consejos! Lo de N<<M lo pensé luego así que voy a ver si lo dejo más apañado :)
edito: Aquí la solución sin errores:
senderID2 = channel.Service_ID + ((uint64_t)channel.Audio_PID<<16) + ((uint64_t)(channel.TunerType + 1)<<29) + ((uint64_t)channel.TransportStream_ID<<32) + ((uint64_t)((channel.TunerType-1)*500*10)<<48) + ((uint64_t)(channel.Flags & (1 << 3)?1:2)<<61);
Segata Sanshiro
17/08/2012, 18:59
¿Y de qué decodificador de TDT estás haciendo el firmware? :D
¿Y de qué decodificador de TDT estás haciendo el firmware? :D
Es un PVR para usar el DVBViewer con el XBMC:
http://img.photobucket.com/albums/v295/_A600/xbmc/PVR1.png
Tengo otro problemilla:
double delphiTimeStart = 1345341600.0/86400.0;
devuelve el valor correcto: 15571.083333333334
pero
double var1 = 1345341600.0;
double delphiTimeStart = var1/86400.0;
me devuelve 15571.083007812500
¿Alguien sabe qué pasa aquí?
edito:
Si declaro las variables como globales sí obtengo el resultado correcto, pero como locales no :(
El caso es que este simple programa con variables locales:
#include <stdio.h>
void main()
{
double var1 = 1345341600.0;
double var2 = var1/86400.0;
printf("Resultado = %f\n", var2);
}
sí funciona, así que npi de por qué la DLL que carga el XBMC no. Estas son las cosas inexplicables que le comen a uno la moral :(
Una pregunta, ya que hace un tiempo que no toco C.
Entiendo que pow y powf sirven para elevar x a y, pero su funcion es crear ids con mascaras de bits o para que lo haces asi?
Me ha picado la curiosidad xD
Entiendo que pow y powf sirven para elevar x a y, pero su funcion es crear ids con mascaras de bits o para que lo haces asi?
Para eso mismo. Estos son los datos que saco:
Bit 0...15 ServiceID
Bit 16...28 AudioPID
Bit 29...31 TunerType + 1
// neu //
Bit 32...47 TransportstreamID
Bit 48...60 OrbitalPos
Bit 61...62 TV/Radio Flag (0 = undefined, 1 = TV, 2 = Radio)
Muchas gracias, nunca se me habria ocurrido crear IDS con mascaras usando esas funciones, es mas, he mirado ejercicios que tengo de mascaras y lo hago de una forma mucho mas burda.
Pasando a lo que estas haciendo, tiene soporte para multiples sintonizadores?Es un trabajo muy grande ese que estas haciendo.
Siempre pense que xmbc usaba lenguajes de script para toda esa logica, y me entero que va en C :D
Pasando a lo que estas haciendo, tiene soporte para multiples sintonizadores?
Sí. Yo tengo una tarjeta de SAT y un pincho TDT y acabo de pedir un motor para la paellera para sacarle todo el jugo.
Es un trabajo muy grande ese que estas haciendo.
Ni de coña. Estoy usando un PVR ya existente (el Vu+) que voy modificando con ñapas para que funcione con el DVBViewer :D
Uso Visual Studio con las optimizaciones desactivadas. Como digo más arriba, este código funciona:
#include <stdio.h>
void main()
{
double var1 = 1345341600.0;
double var2 = var1/86400.0;
printf("Resultado = %f\n", var2);
}
Pero el mismo código, incrustado en una función del PVR no.
Necesito esa función para convertir de un time_t a un floatdatetime que es lo que necesita la API del DVBViewer: Delphitime = (unixtime/86400)+25569, siendo la parte entera los días y la parte decimal los segundos de un día, pero con los resultados que obtengo me salen variaciones de minutos inaceptables.
Al final lo que he hecho ha sido convertir el time_t con gmtime y sacar los datos de ahí, pero me parece un churro de solución.
Con el llvm 3.0 y el gcc 4.2 dan el mismo resultado.
Ten en cuenta que en los x86 (no se desde que version) independientemente de que uses floats o doubles, internamente usa numeros de 80bits y al final hace el redondeo a double o float.
Si la operacion fuese mas larga tendria sentido que te pudieran dar valores distintos por redondeos internos, pero en este caso la verdad es que no lo entiendo.
¡Solucionado!
Mirando las opciones de compilación de Visual Studio he visto que las optimizaciones para SSE2 no estaban activadas en el proyecto de la DLL. Ahora sí que me da los valores correctos, así que gracias a id6490 por ponerme sobre la pista :)
*****,esto es chino para el 99% de la poblacion.
Powered by vBulletin® Version 4.2.5 Copyright © 2025 vBulletin Solutions Inc. All rights reserved.