¿Por qué los tipos enteros rápidos son más rápidos que los otros tipos enteros?

107

En ISO / IEC 9899: 2018 (C18), se establece en 7.20.1.3:

7.20.1.3 Tipos enteros de ancho mínimo más rápidos

1 Cada uno de los siguientes tipos designa un tipo entero que es generalmente más rápido 268) para funcionar con entre todos los tipos de enteros que tienen al menos la anchura especificada.

2 El nombre typedef int_fastN_tdesigna el tipo entero con signo más rápido con un ancho de al menos N. El nombre typedef uint_fastN_tdesigna el tipo entero sin signo más rápido con un ancho de al menos N.

3 Se requieren los siguientes tipos:

int_fast8_t, int_fast16_t, int_fast32_t, int_fast64_t, uint_fast8_t, uint_fast16_t, uint_fast32_t,uint_fast64_t

Todos los demás tipos de este formulario son opcionales.


268) No se garantiza que el tipo designado sea el más rápido para todos los propósitos; Si la implementación no tiene bases claras para elegir un tipo sobre otro, simplemente elegirá algún tipo de entero que satisfaga los requisitos de firma y ancho.


Pero no se dice por qué estos tipos enteros "rápidos" son más rápidos.

  • ¿Por qué estos tipos enteros rápidos son más rápidos que los otros tipos enteros?

Etiqueté la pregunta con C ++, porque los tipos enteros rápidos también están disponibles en C ++ 17 en el archivo de encabezado de cstdint. Desafortunadamente, en ISO / IEC 14882: 2017 (C ++ 17) no existe tal sección sobre su explicación; Había implementado esa sección de otra manera en el cuerpo de la pregunta.


Información: en C, se declaran en el archivo de encabezado de stdint.h.

RobertS apoya a Monica Cellio
fuente
24
El punto clave aquí es que estos tipos enteros no son tipos separados, mágicamente más rápidos. Son solo alias para cualquier tipo normal existente que sea el más rápido en esa máquina para esa operación.
mtraceur
3
El compilador emite códigos de operación de CPU para cargar, almacenar, enmascarar y modificar ubicaciones de memoria y registros de tamaños específicos; eso es todo lo que ve la CPU. El sistema operativo no tiene nada que ver con eso. Es todo lo que hace el compilador, exactamente como si usted mismo hubiera especificado el tipo de definición dado. ( Supongo que un compilador puede procesarlo internamente de manera diferente, tal vez de manera más eficiente, si eso es posible) que un usuario escriba def, siempre y cuando no haya una diferencia visible en el comportamiento.
Peter - Vuelva a instalar a Monica el
1
@ RobertS-ReinstateMonica Para ser precisos, estos "alias" son solo typedefdeclaraciones. Por lo general , se realiza en el nivel de biblioteca estándar. Por supuesto, el estándar C no impone una restricción real sobre lo que typedefdeben hacer, por lo que , por ejemplo, una implementación típica es utilizar int_fast32_tun sistema typedefde int32 bits, pero un compilador hipotético podría, por ejemplo, implementar un __int_fasttipo intrínseco y prometer hacer algo elegante optimizaciones para elegir el tipo de máquina más rápido caso por caso para las variables de ese tipo, y luego la biblioteca podría typedefhacerlo.
mtraceur
1
@ RobertS-ReinstateMonica Sí, es cierto. Obtiene programas de máximo rendimiento con indicadores de compilación específicos de arquitectura que hacen que el binario sea menos portátil.
Peter - Restablece a Mónica el
1
@ Roberts-ReinstateMonica Será más eficiente en la plataforma que fue compilado para , no necesariamente en .
HABO

Respuestas:

152

Imagine una CPU que realiza solo operaciones aritméticas de 64 bits. Ahora imagine cómo implementaría una adición de 8 bits sin signo en dicha CPU. Implicaría necesariamente más de una operación para obtener el resultado correcto. En dicha CPU, las operaciones de 64 bits son más rápidas que las operaciones en otros anchos enteros. En esta situación, todo Xint_fastY_tpodría presumiblemente ser un alias del tipo de 64 bits.

Si una CPU admite operaciones rápidas para tipos enteros estrechos y, por lo tanto, un tipo más ancho no es más rápido que uno más estrecho, entonces Xint_fastY_tno será un alias del tipo más ancho que el necesario para representar todos los bits Y.

Por curiosidad, verifiqué los tamaños en una implementación particular (GNU, Linux) en algunas arquitecturas. Estos no son los mismos en todas las implementaciones en la misma arquitectura:

┌────╥───────────────────────────────────────────────────────────┐
 Y     sizeof(Xint_fastY_t) * CHAR_BIT                         
    ╟────────┬─────┬───────┬─────┬────────┬──────┬────────┬─────┤
     x86-64  x86  ARM64  ARM  MIPS64  MIPS  MSP430  AVR 
╞════╬════════╪═════╪═══════╪═════╪════════╪══════╪════════╪═════╡
 8   8       8    8      32   8       8     16      8   
 16  64      32   64     32   64      32    16      16  
 32  64      32   64     32   64      32    32      32  
 64  64      64   64     64   64      64    64      64  
└────╨────────┴─────┴───────┴─────┴────────┴──────┴────────┴─────┘

Tenga en cuenta que aunque las operaciones en los tipos más grandes pueden ser más rápidas, estos tipos también ocupan más espacio en la memoria caché y, por lo tanto, su uso no necesariamente produce un mejor rendimiento. Además, uno no siempre puede confiar en que la implementación haya tomado la decisión correcta en primer lugar. Como siempre, se requiere medir para obtener resultados óptimos.


Captura de pantalla de la tabla, para usuarios de Android:

Captura de pantalla de la tabla de arriba

(Android no tiene caracteres de dibujo de cuadro en la fuente mono - ref )

eerorika
fuente
Los comentarios no son para discusión extendida; Esta conversación se ha movido al chat .
Samuel Liew
@RobertSsupportsMonicaCellio No. "no es igual en todas las arquitecturas" también es cierto, pero es inmediatamente evidente a partir de los datos mostrados, por lo que no consideraría necesario decir lo obvio. Solo he mostrado valores de una implementación, y de hecho otros tendrán diferentes opciones. Verifique por ejemplo x86-64 en windows. Encontrarás diferentes tamaños en comparación con lo que se muestra aquí.
Eerorika
@RobertSsupportsMonicaCellio En mi opinión, estos comentarios son relevantes para la respuesta, y apropiados aquí. Dejaría que un moderador los moviera, si sienten la necesidad de hacerlo.
Eerorika
11

No lo son, al menos no de manera confiable.

Los tipos rápidos son simplemente typedefs para los tipos regulares, sin embargo, depende de la implementación cómo definirlos. Deben tener al menos el tamaño solicitado, pero pueden ser más grandes.

Es cierto que en algunas arquitecturas algunos tipos enteros tienen un mejor rendimiento que otros. Por ejemplo, las primeras implementaciones de ARM tenían instrucciones de acceso a la memoria para palabras de 32 bits y para bytes sin signo, pero no tenían instrucciones para medias palabras o bytes con signo. Las instrucciones de media palabra y de byte firmado se agregaron más tarde, pero aún tienen opciones de direccionamiento menos flexibles, ya que tuvieron que colocarse en el espacio de codificación de reserva. Además, todas las instrucciones de procesamiento de datos reales en ARM funcionan con palabras, por lo que en algunos casos puede ser necesario enmascarar valores más pequeños después del cálculo para obtener resultados correctos.

Sin embargo, también existe la preocupación competitiva de la presión de caché, incluso si se necesitan más instrucciones para cargar / almacenar / procesar un valor menor. El valor más pequeño aún puede funcionar mejor si reduce la cantidad de errores de caché.

Las definiciones de los tipos en muchas plataformas comunes no parecen haber sido pensadas. En particular, las plataformas modernas de 64 bits tienden a tener un buen soporte para enteros de 32 bits, aunque los tipos "rápidos" a menudo son innecesariamente de 64 bits en estas plataformas.

Además, los tipos en C se convierten en parte de la plataforma ABI. Entonces, incluso si un proveedor de plataforma descubre que tomó decisiones tontas, es difícil cambiar esas elecciones tontas más adelante.

Ignora los tipos "rápidos". Si realmente le preocupa el rendimiento de los enteros, compare su código con todos los tamaños disponibles.

lavado
fuente
7

Los tipos rápidos no son más rápidos que todos los demás tipos enteros; de hecho, son idénticos a algún tipo entero "normal" (son solo un alias para ese tipo), cualquiera que sea el tipo más rápido para mantener un valor de al menos esa cantidad de bits.

Solo depende de la plataforma para qué tipo de entero cada tipo rápido es un alias.

Chris Dodd
fuente