Tengo una lista bastante larga de números positivos de coma flotante ( std::vector<float>
, tamaño ~ 1000). Los números se ordenan en orden decreciente. Si los sumo siguiendo el orden:
for (auto v : vec) { sum += v; }
Supongo que puedo tener algún problema de estabilidad numérica, ya que cerca del final del vector sum
será mucho mayor que v
. La solución más fácil sería atravesar el vector en orden inverso. Mi pregunta es: ¿es tan eficiente como el caso avanzado? ¿Me faltará más caché?
¿Hay alguna otra solución inteligente?
c++
floating-point
precision
Ruggero Turra
fuente
fuente
Respuestas:
Así que pruébalo. Actualmente tiene un problema hipotético, es decir, no hay ningún problema.
Si realiza la prueba y la hipótesis se materializa en un problema real , entonces debería preocuparse por solucionarlo.
Es decir, la precisión de punto flotante puede causar problemas, pero puede confirmar si realmente lo hace para sus datos, antes de priorizar eso sobre todo lo demás.
Mil flotadores son 4Kb: cabe en la memoria caché de un sistema moderno de mercado masivo (si tiene otra plataforma en mente, díganos de qué se trata).
El único riesgo es que el prefetcher no lo ayudará al iterar hacia atrás, pero, por supuesto, su vector ya puede estar en caché. Realmente no puede determinar esto hasta que realice un perfil en el contexto de su programa completo, por lo que no tiene sentido preocuparse hasta que tenga un programa completo.
No se preocupe por las cosas que podrían convertirse en problemas, hasta que realmente se conviertan en problemas. A lo más, vale la pena señalar posibles problemas y estructurar su código para que pueda reemplazar la solución más simple posible con una cuidadosamente optimizada más adelante, sin volver a escribir todo lo demás.
fuente
Marqué en el banco su caso de uso y los resultados (ver imagen adjunta) apuntan a la dirección en la que no hay ninguna diferencia de rendimiento para avanzar o retroceder.
Es posible que también desee medir en su compilador de hardware +.
Usar STL para realizar la suma es tan rápido como el bucle manual sobre datos, pero mucho más expresivo.
use lo siguiente para la acumulación inversa:
mientras que para la acumulación hacia adelante:
fuente
state
bucle está cronometrada.Sí, es eficiente. La predicción de sucursales y la estrategia de caché inteligente de su hardware están ajustadas para acceso secuencial. Puede acumular su vector de manera segura:
fuente
Para este propósito, puede usar el iterador inverso sin ninguna transposición en su
std::vector<float> vec
:O haga el mismo trabajo usando algortithm estándar:
El rendimiento debe ser el mismo, solo cambió la dirección de derivación de su vector
fuente
Si por estabilidad numérica quiere decir precisión, entonces sí, puede terminar con problemas de precisión. Dependiendo de la proporción de los valores más grandes a los más pequeños, y sus requisitos de precisión en el resultado, esto puede o no ser un problema.
Si desea tener una alta precisión, considere la suma de Kahan : esto utiliza un flotador adicional para la compensación de errores. También hay suma por pares .
Para un análisis detallado de la compensación entre precisión y tiempo, consulte este artículo .
ACTUALIZACIÓN para C ++ 17:
Algunas de las otras respuestas mencionan
std::accumulate
. Desde C ++ 17 existen políticas de ejecución que permiten paralelizar algoritmos.Por ejemplo
Esto debería hacer que la suma de conjuntos de datos grandes sea más rápida a costa de errores de redondeo no deterministas (supongo que el usuario no podrá determinar la partición de subprocesos).
fuente