Actualmente estoy trabajando en un sistema de procesamiento numérico que se implementará en un entorno de rendimiento crítico. Toma entradas en forma de matrices numéricas (estas usan la eigen
biblioteca, pero para el propósito de esta pregunta que tal vez sea irrelevante), y realiza un rango de cálculos numéricos (productos de matriz, concatenaciones, etc.) para producir salidas.
Todos los arreglos se asignan estáticamente y sus tamaños se conocen en tiempo de compilación. Sin embargo, algunas de las entradas pueden ser inválidas. En estos casos excepcionales , todavía queremos que se calcule el código y aún queremos que se utilicen salidas no "contaminadas" por valores no válidos.
Para dar un ejemplo, tomemos el siguiente ejemplo trivial (este es un pseudocódigo):
Matrix a = {1, 2, NAN, 4}; // this is the "input" matrix
Scalar b = 2;
Matrix output = b * a; // this results in {2, 4, NAN, 8}
La idea aquí es que 2, 4 y 8 son valores utilizables, pero la NAN debe indicar al destinatario de los datos que esa entrada estuvo involucrada en una operación que involucró un valor no válido, y debería descartarse (esto se detectará a través de un std::isfinite(value)
verificar antes de usar el valor).
¿Es esta una forma sólida de comunicar y propagar valores inutilizables, dado que el rendimiento es crítico y la asignación de almacenamiento dinámico no es una opción (y tampoco lo son otras construcciones que consumen recursos como boost::optional
punteros)?
¿Hay mejores formas de hacer esto? En este punto, estoy bastante contento con la configuración actual, pero esperaba obtener algunas ideas nuevas o críticas productivas de la implementación actual.
Respuestas:
Este es un camino completamente razonable. Tenga en cuenta también que hay máscaras de bits múltiples que se interpretan como NaN. Hay dos tipos principales de NaN: señalización (que puede generar una excepción cuando se crean, dependiendo de su configuración) y silenciosa (que nunca lo hace). Sin embargo, incluso dentro de NaN silenciosos, hay máscaras de bits múltiples que corresponden a NaN silencioso. Si quieres meterte realmente en ello, puedes crear tus propios NaN que son distintos de los NaN normales. Por ejemplo, podría usar un patrón de bits específico que correspondería a NA (que es un concepto diferente de NaN).
En cuanto a su punto sobre la contaminación. Esto se vuelve mucho más complicado. Generalmente, cualquier operación matemática que involucre NaN resulta en NaN. En otras palabras, NaN es contagioso. En algunos casos, esto es lo que quieres. En otros, no lo es. Por ejemplo, suponga que le pidieron la media del vector que le dio. ¿Es NaN o 7/3? Sin embargo, el producto vectorial escalar * que proporcionó funcionará exactamente como lo desea, y tampoco necesita hacer ninguna
std::isfinite
comprobación. Simplemente multiplique los números y el NaN saldrá automáticamente, por lo que es bastante eficiente. Sin embargo, si desea obtener una media de 7/3 para su vector, debe ser más inteligente, ya que hacerlo ingenuamente dará como resultado NaN. Si bien no puedo decirte cómo hacer una implementación rápida de esto, numpy tiene uno y es de código abierto, por lo que puedes ver eso.fuente
A mí me parece bien, siempre y cuando haya arreglado su modelo de coma flotante, y haya dicho semántica NaN.
IEEE 754 es suficiente en su caso.
http://en.m.wikipedia.org/wiki/Single-precision_floating-point_format
/programming/5777484/how-to-check-if-c-compiler-uses-ieee-754-floating-point-standard
fuente