Simulaciones eternas sin sentido

Technorati Tags: , ,

Mismo escenario, mismas condiciones de los nodos y los enlaces. Sólo varía la carga global.

Con carga normalizada de 1, se transmiten 8.998.692.463 ráfagas en 3.000 segundos de simulación. La simulación tarda en total 118611 segundos, menos de un día y medio.

Con carga normalizada 0,85, va por el segundo 2.300 y lleva transmitidas 5.867.386.501 ráfagas. La simulación lleva ejecutándose toda la semana.

Sospecho que esto tiene algo que ver:

Nivel de carga: 1 => Tiempo medio entre llegadas: 1.0000000000000001e-05
Nivel de carga: 0.85 => Tiempo medio entre llegadas: 1.1764705882352942e-05

Share

Excepciones de coma flotante y verificación de variables

Technorati Tags: , , ,

Cualquiera que haya programado cierto tiempo y haya tenido que realizar divisiones con variables que no se sabe a priori qué valor van a tomar sabe que, tarde o temprano, ocurrirá alguna excepción de coma flotante, debida a un intento de dividir por cero (porque la variable en ese momento tiene el valor cero, o uno muy cercano), terminándose la ejecución del programa.

Para evitar este problema, lo habitual es colocar una condición antes de realizar la operación de división y darle un valor fijo en caso de que el divisor sea cero. Algo tan sencillo como esto:

if (proporcion_[slot_out] > 0.0) {
deficit_[i] += (long long) (0.5 + (double) longitud_paquete * proporcion_[i] / proporcion_[slot_out]);
}

Debería ser suficiente para evitar que ocurriera algún problema ¿verdad? Pues no, ni mucho menos. Llevo unas semanas haciendo simulaciones con el código tal cual está. Hoy he cambiado a una red más grande y no hacía más que fallar, así que me he metido con el gdb y he encontrado que el fallo está en ese punto. Para comprobar que no entraba en ese ‘if’ he hecho lo que cualquiera: presentar por pantalla el valor de esa variable:

if (proporcion_[slot_out] > 0.0) {
printf(«Proporcion = %f\n», proporcion_[slot_out]);fflush(stdout);
// se puede hacer también sin redondear
deficit_[i] += (long long) (0.5 + (double) longitud_paquete * proporcion_[i] / proporcion_[slot_out]);
}

El resultado era el siguiente:

Proporcion = 0.000000
Exepción de coma flotante

Podríamos hablar del fallo horrográfico, pero no, a mí me gustaría saber por qué me presenta por pantalla el valor de la variable si se supone que al valer 0, no entra en el ‘if’. Arrea, que la precisión es finita, y los números que puede manejar la máquina pueden no ser representables con ese nivel de precisión. Hagamos un cambio en el código: que en lugar de mostrar con formato %f lo haga con formato %g (notación exponencial)…

if (proporcion_[slot_out] > 0.0) {
printf(«Proporcion = %g\n», proporcion_[slot_out]);fflush(stdout);
// se puede hacer también sin redondear
deficit_[i] += (long long) (0.5 + (double) longitud_paquete * proporcion_[i] / proporcion_[slot_out]);
}

El resultado, señoras y señores, no podía ser más preocupante:

Proporcion = 1.27e-319
Exepción de coma flotante

Teniendo en cuenta que si el valor de la proporción no es calculada en base a unos parámetros, su valor se fuerza a 0, es cuanto menos preocupante. Para arreglarlo nada como compararlo con un número muy pequeño, pero no demasiado, y eso porque trabajo con proporciones relativamente grandes (menores de 1, pero mayores de 1e-10, seguro), que si no, ya me iban a dar bien dado.

Share

Programación de ns: problemas de mezclar C++ con Tcl sin dosis elevadas de cafeína

Technorati Tags: , , ,

Las cosas que pasan cuando se programan módulos de ns, que requiere mezclar los lenguajes C++ y Tcl, que tienen una sintaxis bastante diferente.

ns@autoslocos:~/ns-allinone-2.29-dev/ns-2.29$ make
g++ -c -Wall -DTCP_DELAY_BIND_ALL -DNO_TK -DTCLCL_CLASSINSTVAR -DNDEBUG -DLINUX_TCP_HEADER -DUSE_SHM -DHAVE_LIBTCLCL -DHAVE_TCLCL_H -DHAVE_LIBOTCL1_11 -DHAVE_OTCL_H -DHAVE_LIBTK8_4 -DHAVE_TK_H -DHAVE_LIBTCL8_4 -DHAVE_TCL_H -DHAVE_CONFIG_H -DNS_DIFFUSION -DSMAC_NO_SYNC -DCPP_NAMESPACE=std -DUSE_SINGLE_ADDRESS_SPACE -Drng_test -I. -I/home/ns/ns-allinone-2.29/tclcl-1.17 -I/home/ns/ns-allinone-2.29/otcl-1.11 -I/home/ns/ns-allinone-2.29/include -I/home/ns/ns-allinone-2.29/include -I/usr/include/pcap -I./tcp -I./sctp -I./common -I./link -I./queue -I./adc -I./apps -I./mac -I./mobile -I./trace -I./routing -I./tools -I./classifier -I./mcast -I./diffusion3/lib/main -I./diffusion3/lib -I./diffusion3/lib/nr -I./diffusion3/ns -I./diffusion3/filter_core -I./asim/ -I./qs -I./diffserv -I./satellite -I./wpan -I./amor -I./OBS -I./monitor -o amor/rtProtoamor.o amor/rtProtoamor.cc
amor/rtProtoamor.cc: In member function ‘virtual void VarianceTimer::expire(Event*)’:
amor/rtProtoamor.cc:32: error: expected `(‘ before ‘{’ token
amor/rtProtoamor.cc:33: error: expected `;’ before string constant
amor/rtProtoamor.cc:33: aviso: statement es una referencia, no una llamada, a la función ‘puts’
amor/rtProtoamor.cc:33: aviso: statement no tiene efecto
amor/rtProtoamor.cc:34: error: expected primary-expression before ‘else’
amor/rtProtoamor.cc:34: error: expected `;’ before ‘else’
make: *** [amor/rtProtoamor.o] Error 1

Código causante del error:

void AMORTimer::expire (Event *e) {
Tcl & tcl = Tcl::instance();
tcl.evalf(«%s calcula-costes», agente_->name());
const char * resultString = tcl.result();
int cambios = atoi(resultString);

if {$cambios == 0} {
puts «No hay cambios»
} else {
puts «Hay cambios»
}
resched(delay);
}

Cualquier parecido con la realidad es pura coincidencia.

Share