Cómo escribir código más eficiente

¿Cuestión del siglo? Básicamente, quiero saber cuál sería más eficiente si escribiera este código como varias variables diferentes o si usara arreglos pequeños.

int x = 34; int y = 28; int z = 293; 

vs

 double coordinate[3] = {34, 28, 293}; 

Tengo una estructura de coordenadas que usaré de la siguiente manera:

 typedef struct coordinates_t { double x = 0.0; double y = 0.0; double z = 0.0; } coordinates; typedef struct car_t { coordinates start; // car starting point coordinates location; // car current Location coordinates targCarVector; // Vector to car from target coordinates altitude; // Altitude of car coordinates distance; // Distance from car start to current position } car; 

Tendré que hacer cosas como:

 distance = car1.location - car1.start; 

Si no uso una matriz, tendré que tener muchas líneas de código, pero si utilizo una matriz, tendré que usar bucles. ¿Las matrices y los bucles son más intensivos en memoria / CPU? Básicamente estoy tratando de ver cuál es la forma más eficiente de escribir este código.

Gracias, DemiSheep

La primera pregunta es: ¿Quieres optimizarlo? Lo más probable es que no quieras. Al menos no si “siempre codificas como si el tipo que termina manteniendo tu código sea un psicópata violento que sepa dónde vives”. La legibilidad, la claridad de la intención y la capacidad de mantenimiento siempre son lo primero.

La segunda pregunta es: ¿vale la pena optimizarlo ? En el 97% no lo es, según Donald Knuth, y usted no cuestiona a Knuth, ¿verdad? Otra regla común es la regla 80/20, es decir, el 80% del tiempo de ejecución se gasta en el 20% del código. Si optimiza en absoluto, primero el perfil para saber dónde optimizar. Si lo adivinas, te equivocas. Período.

La tercera pregunta es: ¿ PUEDES optimizarlo? No, no puedes, al menos no tan fácilmente. ¿Crees que eres más inteligente que los cientos de progtwigdores que escribieron tu comstackdor durante muchas décadas? Tu no eres Si se puede optimizar la implementación real de su algoritmo y las estructuras de datos, puede asumir que su comstackdor puede hacerlo por sí solo. El comstackdor puede realizar el desenrollado de bucles, el reordenamiento de instrucciones, la combinación de variables con el tiempo de vida no superpuesto, la optimización del diseño de estructuras y mucho más, y en esta era, es incluso mejor que la mayoría de los progtwigdores de ensamblajes en la mayoría de los casos. E incluso si hay un poco de potencial, es mejor que te concentres en implementar un mejor algoritmo. Ningún comstackdor puede convertir O (n ^ 2) en O (n log n), pero tal vez lo hizo un científico informático inteligente y usted puede implementar su algoritmo para obtener un rendimiento mucho mejor que cualquier microoptimización.

¿Es la eficiencia más importante que la facilidad de mantenimiento y la legibilidad? La respuesta es no. Incluso si tiene una aplicación de tiempo crítico, pasará el 90% del tiempo en menos del 10% del código, por lo que solo el 10% debe codificarse de la manera más eficiente posible.

Si no ha medido y encontrado cuál es el 10% del culpable, es casi seguro que estará optimizando el código que no lleva mucho tiempo de ejecución en primer lugar. Esto es una pérdida de tiempo.

Tendrías que medir para cada plataforma que quieras hacer esta.

Sin embargo, no creo que esto haga ninguna diferencia notable en absoluto. (Tal vez, excepto por algunas plataformas integradas. Esa es un área que no conozco mucho). Entonces, primero escriba el código de la manera más fácil de leer y entender . Luego mida si su código va a disminuir, y use un generador de perfiles para encontrar los lugares exactos donde el progtwig pasa mucho tiempo. Luego intente mejorarlos, midiendo después de cada cambio para ver qué efecto tuvo.

Mejorar la velocidad de una base de código fácil de entender es mucho más fácil que entender una base de código que está plagada de “optimización” prematura e innecesaria.

Las mejoras medibles en el tiempo de ejecución generalmente provienen de cambios algorítmicos , no de microoptimizaciones como esta. Pasa tu tiempo tratando de encontrar mejores algoritmos.

Si realmente desea micro-optimizar esto, use las capacidades de instrucción SIMD de su CPU. Si está utilizando una plataforma x86, puede usar instrucciones MMX o SSE para hacer aritmética vectorial en lugar de agregar cada parte de la coordenada individualmente (es posible que su comstackdor no las genere sin interruptores especiales de línea de comandos o ensamblaje en línea). Esto probablemente supondrá una mayor aceleración que el cambio entre variables individuales y una matriz. Digo “probablemente” porque no hay forma de saberlo con certeza sin intentarlo en ambos sentidos y sin medir el tiempo de ejecución.

Usa una matriz, comstack con -funroll-loops. Obtienes los beneficios de ambos.

Los comstackdores pueden “desenrollar” los bucles si creen que ayudará. Así que el comstackdor podría reemplazar silenciosamente el siguiente código:

 for (i = 0; i < 3; ++i) { c[i] = a[i] - b[i]; } 

con:

 c[0] = a[0] - b[0]; c[1] = a[1] - b[1]; c[2] = a[2] - b[2]; 

El comstackdor hará su mejor estimación de si vale la pena hacer esto, teniendo en cuenta los costos de las operaciones involucradas y los indicadores de optimización que proporciona.

No hay una respuesta simple para "¿cuál será más rápido?", Pero si existiera, puede estar seguro de que, con la máxima optimización, su comstackdor la usaría.

En caso de duda, codifique prototipos para cada uno y perfílelos. Para las cosas en este nivel, predeciré que cualquier diferencia en el rendimiento disminuirá en el ruido. Use lo que tenga sentido y transmita más claramente la intención del diseño.

En orden descendente de importancia, el código debe ser

  1. Correcto: no importa qué tan rápido sea su código si le da la respuesta incorrecta o si hace algo incorrecto;
  2. Mantenible: no importa qué tan rápido sea su código si no puede arreglarlo o modificarlo para satisfacer nuevos requisitos;
  3. Robusto: no importa qué tan rápido sea su código si se vuelca el núcleo en el primer indicio de entrada poco fiable;

En algún lugar después de esto, puedes empezar a preocuparte por el rendimiento.

La respuesta del siglo es.

No pongas el carro delante del caballo.

En otras palabras, perfil primero.

Todo el mundo “sabe” esto, pero una gran categoría de preguntas son de la forma “¿Cuál es más rápido, X o Y?”

Esto provoca conjeturas y, cuando le preocupa el rendimiento, las conjeturas no valen mucho, porque si tiene un problema de rendimiento, es probable que se encuentre en otro lugar.

Como siempre, necesitará un perfil de su código para estar seguro.

Habiendo dicho eso, sugeriría ir a una matriz y bucles: su código debe ser más conciso / mantenible y el comstackdor debería ser capaz de hacer un buen trabajo en la optimización / desenrollado de todos los pequeños bucles de tamaño constante, que es efectivamente lo que estaría haciendo a mano si usara las coordenadas x, y, z para cada vector.

En una nota completamente sin relación, veo que tu coche tiene altitud. ¿Es un coche volador? Si es así, entonces definitivamente +1 para la aplicación fresca.

Vaya por la forma más correcta, que sería utilizar bucles y matrices, ninguno de los cuales resultará en un mayor uso de la memoria (menos uso, ya que la memoria requerida por todos esos car1, car2, car3 … las instrucciones serán más) – y CPU En cuanto al uso, se ven las más pequeñas diferencias.

Indique su código y descubra cuál es el problema principal de la ineficiencia. La eficiencia se puede medir mediante la ejecución del código en tiempo de ejecución.

Algunas herramientas para hacerlo están disponibles como código abierto como gprof .

Normalmente no me preocupo por la eficiencia …

Un lugar donde se aceleran las cosas es si hago una búsqueda de un valor numérico. Diga que quiero encontrar un número de cuenta “188335344” que sucederá mucho más rápido que la búsqueda de caracteres alfabéticos. La búsqueda debe cambiar cada línea de texto a mayúsculas, ya que busca valores no numéricos. No es así para los números.

Bastante más rápido en realidad.

Cualquier cosa que requiera la entrada del usuario puede ser extremadamente ineficiente y no importará un ápice.

Muestro el tiempo transcurrido al final de cada búsqueda. Por lo tanto, el código más antiguo puede compararse con cambios más recientes.