¿Es bueno usar aritmética binaria en un código C ++ como "estilo C"?

7

Me gusta el hecho de que el lenguaje C le permita usar la aritmética binaria de manera explícita en su código, a veces el uso de la aritmética binaria también puede darle una pequeña ventaja en términos de rendimiento; pero desde que comencé a estudiar C ++ realmente no puedo decir cuánto he visto el uso explícito de algo así en un código C ++, algo así como una estructura de puntero a puntero o una instrucción para saltar a un valor de índice específico a través de la aritmética binaria .

¿La aritmética binaria sigue siendo importante y relevante en el mundo de C ++? ¿Cómo puedo optimizar mi aritmética y / o un acceso a un índice específico? ¿Qué pasa con el C ++ y la forma en que se ordenan los bits de acuerdo con el estándar?

¿

... o he echado un vistazo a las convenciones de codificación equivocadas ...?

    
pregunta user827992 25.06.2012 - 13:33

9 respuestas

25

En resumen: No, no es bueno usar "aritmética binaria" (en el sentido que la pregunta lo hace) o "estilo C" en C ++ .

¿Qué te hace creer que la aritmética bitwise sería más rápida realmente? Puedes lanzar tus operaciones bitwise en todo el código, pero ¿qué lo haría más rápido?

El problema es que casi cualquier cosa trivial que intenta resolver, se puede resolver más fácilmente con las funciones estándar de alto nivel (incluida la biblioteca estándar, los algoritmos STL y STL). En algunos casos específicos, es posible que desee cambiar los bits individuales, por ejemplo, al trabajar con bitmasks . O almacenar datos muy compactos, por ejemplo, al escribir un algoritmo de compresión, un formato de archivo denso o trabajar, por ejemplo, con sistemas integrados.

Si te preocupa el rendimiento, siempre escribe primero un algoritmo simple y trivial. Sólo haz que funcione. Luego, mida el tiempo que toma su algoritmo con una entrada típica. Ahora, si en este punto sientes que es demasiado lento, solo entonces puedes intentar optimizarlo a mano con estos trucos de "aritmética de bits". Y una vez hecho, mida si su código es más rápido. Lo más probable es que no lo sea, a menos que realmente sepa lo que está haciendo en esa situación / caso específico.

Francamente, la mejor manera de entender este tipo de construcciones de bajo nivel que tratan con el rendimiento es estudiar el lenguaje ensamblador. Realmente te hace darte cuenta de que no, escribir un wizzcode de manipulación de bits no es tan rápido como usar ese sort(begin(v),end(v)) . El hecho de que usted opere a un nivel bajo no significa que opere rápido. En general, los algoritmos son más importantes que los detalles de implementación.

Básicamente, cualquiera que sea el " estilo C " significa, por favor , aléjate de él cuando escribas C ++. Son dos idiomas completamente diferentes. No mezclarlos

Bjarne Stroustrup dio una gran charla sobre el estilo de C ++ en la conferencia GoingNative 2012 de Microsoft este febrero, por favor eche un vistazo: enlace

Especialmente las partes entre 10 y 15 minutos son excelentes, cuando habla sobre el código antiguo de estilo C en comparación con el estilo moderno de C ++.

    
respondido por el zxcdw 25.06.2012 - 14:34
13
  

por ejemplo, el operador de turno < < o > & gt ;, que es una forma rápida de   calcula "algo por 2" o "algo dividido por 2"

Si estás trabajando en C o C ++, escribe lo que quieres decir. Escriba foo = foo * 2; o foo *= 2; si eso es lo que quiere decir, no foo = foo << 1; . Deje que el compilador se ocupe de encontrar las instrucciones más rápidas de usar y no confunda a las personas que tienen que leer su código con una optimización de mano innecesaria.

    
respondido por el Caleb 25.06.2012 - 18:38
8

Sigue estos pasos:

  1. Escriba el código de la forma más simple y clara posible.
  2. Activa todas las optimizaciones del compilador.
  3. Considere si tiene suficiente conocimiento sobre la CPU objetivo específica y su conjunto de instrucciones (ensamblador). De lo contrario, es probable que tenga dificultades para realizar las optimizaciones manuales y que probablemente no deba intentarlo, ya que es probable que termine de ofuscar el código sin ganancia alguna. También tenga en cuenta que la optimización manual solo es necesaria si su compilador tiene un soporte pobre para la plataforma de destino específica. Como alternativa, puedes probar con otro compilador.

  4. Identifique cuellos de botella de rendimiento. Cómo encontrarlos depende del sistema de destino. En los programas de "alto nivel", como la programación de escritorio, usted evalúa su código a través de herramientas específicas diseñadas para ese propósito, o a través de las funciones API del OS En los programas de "bajo nivel", como los sistemas integrados, normalmente se usa un osciloscopio para medir el rendimiento en tiempo real. En cualquier programa, puede desensamblar el código y ver qué se le ocurrió al compilador.

  5. Si no hay cuellos de botella que afecten el rendimiento de su programa, no necesita hacer nada y puede dejar de leer aquí.
  6. Si hay cuellos de botella que tienen un impacto en su programa, es posible que deba realizar una optimización manual.
  7. ¿Cómo hacer las optimizaciones manuales depende de la CPU de destino, no hay truco universal. Los aspectos más comunes que debe buscar son: aritmética de punto flotante, alineación, tamaños de enteros, división, predicción de rama y amp; manejo de caché de instrucciones, uso de funciones de biblioteca innecesariamente complejas ... y así sucesivamente.
respondido por el user29079 26.06.2012 - 09:57
4

Depende del tipo de código C ++ que estés escribiendo. Cuanto más bajo eres, más relevante se vuelve. El problema con este tipo de preguntas es que todos solo pueden confiar en su propia experiencia y, por lo tanto, si alguien nunca tuvo que hacer este tipo de cosas, no pueden ver por qué otra persona podría necesitar hacerlo.

Aquí está el artículo de Joel "Five Worlds"

    
respondido por el James 25.06.2012 - 17:16
2

Hago uso aritmética binaria en prácticamente TODOS los lenguajes de computadora con los que he programado. Por ejemplo, tome el operador de suma + :

int sum = x + y; // compiler probably implements this as binary arithmetic!

Me resultaría difícil programar en un lenguaje que no admite aritmética, y me cuesta creer que su compilador / intérprete no haya implementado operaciones aritméticas usando aritmética binaria (como usar aritmética de base 10) .

enlace

enlace

enlace

TL; DR: Usa la terminología correcta (bitwise ≠ binary), de lo contrario obtendrás respuestas pendientes como esta.

    
respondido por el Thomas Eding 18.09.2012 - 21:19
1

La aritmética binaria está vinculada a la implementación. Debe tener cuidado con los detalles de la implementación, como la endianidad. Por lo tanto, el uso de operadores binarios no es automáticamente más rápido que el uso de operadores elementales. A menudo, el compilador realizará optimizaciones más relevantes, y un código natural puede ser mejor para el rendimiento y más fácil de leer tanto para el compilador como para el programador.

Por supuesto, hay algunos casos (como la codificación Base64), en los que debe usar esos operadores. Pero la optimización del código con operadores binarios debería ser la última optimización, después de perfeccionar sus algoritmos. Para la programación personal, algunos trucos bonitos ( como este ) pueden ser más rápidos, pero con una programación seria, la legibilidad debería venir primero.

Y, como dice zxcdw , C y C ++ son lenguajes muy diferentes. C ++ tiene más bibliotecas de alto nivel, por lo que los trucos binarios son menos famosos.

    
respondido por el md5 25.06.2012 - 15:11
1

No, no se usa la aritmética binaria en C ++, excepto un "pequeño" detalle: el estándar de C ++ define la semántica del lenguaje en términos de un binario resumen virtual Máquina que debe utilizar el 1er complemento, el 2do complemento o la representación de enteros de magnitud de signo.

    
respondido por el zvrba 25.06.2012 - 17:15
1

Como muchos ya han mencionado, tenga en cuenta que no optimice prematuramente las cosas . Pero cuando encuentra un código vinculado a la CPU que es un cuello de botella , una de las mejores maneras de entender cuál de sus implementaciones alternativas sería mejor, utilizando Clang C / C ++ - > LLVM IR es una gran idea. Si se siente más cómodo en un navegador web, intente enlace .

El IR (Representación intermedia) generado por Clang y LLVM son instrucciones de máquinas virtuales. Por ejemplo, puede escribir el mismo algoritmo / función aritmética en "estilo C" y "estilo C ++" (¿estoy adivinando "estilo STL"?) Y comparar el IR generado por el compilador. Incluso si su compilador de producto final no se basa en LLVM, el código IR será representativo de qué código se realmente genera y compila. Más allá de IR solo hay optimizaciones de hardware (como la forma en que se implementan las plataformas de aterrizaje de las ramas condicionales) LLVM puede producir ensamblaje de la máquina de destino, si crees que te haría más sabio (pero no recomendaría ir más allá de IR).

    
respondido por el rsms 26.06.2012 - 01:21
0

A veces, varias banderas se agrupan en un solo byte para ahorrar espacio. A veces es prematuro, otras veces crítico.

Microsoft SQL Server almacenará varias columnas del tipo de datos "bit" en el mismo byte. En este caso no es una optimización prematura. Usted ahorra 2 a 8 veces el espacio en disco, para columnas de 2 a 8 bits (esto es un gran problema). También obtienes búsquedas más rápidas (gran problema). También es más probable que pueda almacenar en caché un conjunto de datos en la memoria. Esto es perfecto. Dado que no hay beneficios en la indexación de datos binarios, también puede empaquetar los bits juntos. Y la naturaleza bitwise no está expuesta a los programadores clientes, por lo que todos están contentos.

La API de Windows incluye varias opciones por byte. Manipulas las opciones de visualización con operaciones bitwise. Yo diría que este fue prematuro. También hizo que mucha gente se rindiera en la programación de windows. Pero los programadores que escribieron la API vinieron de los viejos tiempos cuando el espacio estaba muy limitado. En ese momento puede haber sido una buena idea diseñar una API alrededor de la manipulación a nivel de bits.

A los videojuegos cliente / servidor les encanta empaquetar varias banderas en un byte. Por ejemplo, en el servidor el juego calcula tu daño. Enviará los datos de la pantalla al cliente, con varias banderas como si fuera un golpe crítico, si matara al enemigo, etc. La pantalla luego se procesaría con operaciones bitwise. Esto es discutible si es prematuro o no. Pero me inclino a decir que menos es más cuando se empujan datos a través de una red.

    
respondido por el Lord Tydus 19.09.2012 - 03:14

Lea otras preguntas en las etiquetas