Arquitecturas exóticas que preocupan a los comités de normas

154

Sé que los estándares C y C ++ dejan muchos aspectos del lenguaje definidos por la implementación solo porque si hay una arquitectura con otras características, sería muy difícil o imposible escribir un compilador conforme estándar.

Sé que hace 40 años cualquier computadora tenía su propia especificación única. Sin embargo, no conozco ninguna arquitectura utilizada hoy en día donde:

  • CHAR_BIT != 8
  • signed no es el complemento de dos (escuché que Java tenía problemas con este).
  • El punto flotante no cumple con IEEE 754 (Editar: quise decir "no en codificación binaria IEEE 754").

La razón por la que pregunto es que a menudo les explico a las personas que es bueno que C ++ no exija ningún otro aspecto de bajo nivel, como los tipos de tamaño fijo . Es bueno porque, a diferencia de 'otros idiomas', hace que su código sea portátil cuando se usa correctamente (Edición: porque se puede portar a más arquitecturas sin requerir la emulación de aspectos de bajo nivel de la máquina, como por ejemplo, aritmética complementaria de dos en arquitectura de signo + magnitud) . Pero me siento mal porque no puedo señalar ninguna arquitectura específica yo mismo.

Entonces la pregunta es: ¿qué arquitecturas exhiben las propiedades anteriores?

uint*_ts son opcionales.

Yakov Galka
fuente
9
Creo que lo tienes al revés. Si el C ++ fuera obligatorio, digamos, dos complementarios para enteros firmados, haría que el código C ++ sea más portátil y no menos. La cuestión de por qué el comité de estándares de C ++ no exige esto es otra cuestión. Especialmente porque, a pesar de lo que dices, no sería imposible escribir un compilador para una arquitectura no estándar, siempre puedes simular caracteres de 8 bits o dos aritmética complementaria incluso cuando tu plataforma no lo admite directamente.
juan
8
@john: entonces no sería práctico, por lo que un compilador no estándar generaría un código más rápido que uno conforme. Y todavía no veo cómo hace que su código sea más portátil.
Yakov Galka
44
Estoy seguro de que la verdadera razón de que el estándar sea así no es porque sea una solución ideal. Pero en cambio es porque cuando se escribió el estándar, muchos compiladores C y C ++ ya existían, y el comité de estándares no quería rechazar los compiladores existentes.
juan
44
@john: Dudo que "hacer que sea más fácil para los escritores de compiladores" sea una prioridad al crear el estándar C ++ (si lo fuera, estarían haciendo un trabajo horrible, ya que C ++ es uno de los lenguajes más difíciles de analizar y otros aspectos de el lenguaje tampoco lo hace fácil para los escritores de compiladores). Sin embargo, el rendimiento, el amplio soporte de plataforma y la compatibilidad con versiones anteriores son bastante importantes. Y los tres sufrirían si las restricciones que menciona se agregan al estándar.
Sander De Dycker
55
No se trata del compilador sino del hardware. C ++ deja algunas cosas sin especificar para permitir el uso directo de las características del hardware. De todos modos, las aplicaciones de su teléfono no se ejecutarán en un mainframe, por lo que no hay portabilidad, por más que cumpla con el código.
Bo Persson el

Respuestas:

114

Echa un vistazo a este

Servidores Unisys ClearPath Dorado

ofreciendo compatibilidad con versiones anteriores para personas que aún no han migrado todo su software Univac.

Puntos clave:

  • Palabras de 36 bits
  • CHAR_BIT == 9
  • el complemento de uno
  • Punto flotante de 72 bits no IEEE
  • espacio de direcciones separado para código y datos
  • dirigido por palabra
  • sin puntero de pila dedicado

Sin embargo, no sé si ofrecen un compilador de C ++, pero podrían hacerlo .


Y ahora ha aparecido un enlace a una edición reciente de su manual en C:

Manual de referencia de programación del compilador Unisys C

La Sección 4.5 tiene una tabla de tipos de datos con 9, 18, 36 y 72 bits.

tamaño y rango de tipos de datos en el compilador USC C

Bo Persson
fuente
13
Supongo que vacío * debe ser infernal para usar en esa arquitectura.
luiscubal
13
@ybungalobill - Creo char*y void*deben ser del mismo tamaño, y lo suficientemente grande para contener cualquier otro puntero. El resto depende de la implementación.
Bo Persson
22
@ybungalobill: En los compiladores antiguos de Win16, los punteros regulares estaban cerca de los punteros y contenían solo un desplazamiento de 16 bits, por lo tanto sizeof(int*) == 2, pero los punteros lejanos también tenían un selector de 16 bits sizeof(void*) == 4.
Adam Rosenfield
10
Hay, o solía haber, un manual en línea para su compilador de C ++. También vale la pena señalar que esta es solo una de las arquitecturas de mainframe de Unisys: la otra es una arquitectura etiquetada de magnitud firmada de 48 bits (para la cual solo he encontrado un manual en C, no uno en C ++). En cuanto al resto: no creo que sizeof(int*) != sizeof(char*)aquí: ambos son 36 bits. Pero el selector de bytes en el char*está en los bits de orden superior, y se ignora en int*. (Sin embargo, he usado otras máquinas, donde `sizeof (char *)> sizeof (int *).)
James Kanze
16
@ Adam Rosenfield En los compiladores de 16 bits de MS / DOS, tenía "modos" diferentes, y los punteros de datos no eran necesariamente del mismo tamaño que los punteros de función. Pero al menos en los que utilicé, todos los punteros de datos (incluidos void*) siempre tenían el mismo tamaño. (Por supuesto, no podría convertir un puntero de función void*, ya que void*podría ser más pequeño. Pero de acuerdo con el estándar, tampoco puede hacerlo hoy.)
James Kanze
51

Ninguno de sus supuestos es válido para mainframes. Para empezar, no conozco un mainframe que use IEEE 754: IBM usa punto flotante base 16, y ambos mainframes Unisys usan base 8. Las máquinas Unisys son un poco especiales en muchos otros aspectos: Bo ha mencionado el 2200 arquitectura, pero la arquitectura MPS es aún más extraña: palabras etiquetadas de 48 bits. (Si la palabra es un puntero o no, depende de un poco en la palabra). Y las representaciones numéricas están diseñadas para que no haya una distinción real entre coma flotante y aritmética integral: el punto flotante es base 8; no requiere normalización y, a diferencia de cualquier otro punto flotante que he visto, coloca el decimal a la derecha de la mantisa, en lugar de a la izquierda, y utiliza la magnitud con signo para el exponente (además de la mantisa). Con los resultados de que un valor de coma flotante integral tiene (o puede tener) exactamente la misma representación de bits que un entero de magnitud con signo. Y no hay instrucciones aritméticas de coma flotante: si los exponentes de los dos valores son ambos 0, la instrucción hace aritmética integral, de lo contrario, hace aritmética de coma flotante. (Una continuación de la filosofía de etiquetado en la arquitectura). Lo que significa que mientrasint puede ocupar 48 bits, 8 de ellos deben ser 0 o el valor no se tratará como un entero.

James Kanze
fuente
44
Los mainframes de IBM (z / Architecture) admiten el punto flotante IEE754.
Nikita Nemkin
1
fyi ver este comentario de twitter
Shafik Yaghmour
66
@Nikita - Lo hacen ahora . Inicialmente era un complemento (costoso) para admitir Java.
Bo Persson
42

El cumplimiento total de IEEE 754 es raro en implementaciones de punto flotante. Y debilitar la especificación en ese sentido permite muchas optimizaciones.

Por ejemplo, el soporte de subnorm difiere entre x87 y SSE.

Las optimizaciones como fusionar una multiplicación y una suma que estaban separadas en el código fuente también cambian ligeramente los resultados, pero es una buena optimización en algunas arquitecturas.

O en x86, el cumplimiento estricto de IEEE puede requerir que se establezcan ciertos indicadores o transferencias adicionales entre los registros de punto flotante y la memoria normal para obligarlo a usar el tipo de punto flotante especificado en lugar de sus flotantes internos de 80 bits.

Y algunas plataformas no tienen flotantes de hardware y, por lo tanto, necesitan emularlos en software. Y algunos de los requisitos de IEEE 754 pueden ser costosos de implementar en software. En particular, las reglas de redondeo pueden ser un problema.

Mi conclusión es que no necesita arquitecturas exóticas para entrar en situaciones en las que no siempre quiere garantizar el cumplimiento estricto de IEEE. Por esta razón, pocos lenguajes de programación garantizan el estricto cumplimiento de IEEE.

CodesInChaos
fuente
77
Otro conjunto de hardware "exótico" son los mainframes de IBM, donde el formato de punto flotante es anterior al estándar IEEE. A diferencia de Java, C ++ todavía puede usar el hardware existente.
Bo Persson
55
IEEE 754 no es totalmente compatible con las GPU.
kerem
3
La falta de cumplimiento estricto de IEEE 754 es una molestia para algunos, pero no creo que esté en el alcance de los problemas que realmente le preocupan al OP.
Omnifarious
3
@Matthieu Dado que esto también está etiquetado como "C", debo mencionar un analizador de C que puede decirle todos los valores que su programa de punto flotante puede tomar con registros de punto flotante de 80 bits derramados en la memoria por capricho del compilador de C. blog.frama-c.com/index.php?post/2011/03/03/cosine-for-real
Pascal Cuoq
2
@MatthieuM .: Es una lástima que ISO / ANSI no permitiera que parámetros variables especifiquen tamaños mínimos / máximos para argumentos de punto flotante y enteros; si lo hubieran hecho, el 80-bit long doublepodría haber sido un tipo útil y de larga vida, ya que el único problema real con el que funcionaba mal printf. El hecho de que el doble extendido almacene el 1 principal acelera explícitamente los cálculos en sistemas que no son FPU y también eliminaría la necesidad de un manejo especial de los valores normales en cualquier contexto que no sea conversiones hacia / desde otros tipos. Lástima que C lo haya printfestropeado todo.
supercat
40

Encontré este enlace que enumera algunos sistemas donde CHAR_BIT != 8. Incluyen

algunos DSP TI tienen CHAR_BIT == 16

Chip BlueCore-5 (un chip Bluetooth de Cambridge Silicon Radio) que tiene CHAR_BIT == 16.

Y, por supuesto, hay una pregunta sobre Stack Overflow: ¿Qué plataformas tienen algo más que caracteres de 8 bits?

En cuanto a los sistemas que no son del complemento a dos, hay una lectura interesante en comp.lang.c ++. Moderada . Resumido: hay plataformas que tienen un complemento o representación de signo y magnitud.

dcn
fuente
55
Dispositivos analógicos SHARC DSP de 32 bits tiene CHAR_BIT=32, y Texas Instruments DSP de TMS32F28xx tiene CHAR_BIT=16. GCC 3.2 para PDP-10 tiene CHAR_BIT=9. Creo que S / 360 también puede tener un carácter no de 8 bits.
osgx
1
Todavía me gustaría un ejemplo para arquitecturas de 'complemento de no dos'. Sobre todo porque sucedió que el CHAR_BITSes un duplicado parcial.
Yakov Galka
Los DSP de TI tienen caracteres de 16 bits solo porque los implementadores lo eligieron (sería un poco más trabajo hacer que funcione correctamente, pero no un IIRC absurdamente difícil, probablemente solo algunos "agujeros" en el andamiaje de codegen en el compilador subyacente) . Entonces no es una razón arquitectónica profunda. El código C funciona en una máquina abstracta. Si todo lo que tiene son INT de 16 bits, almacene dos caracteres en cada uno y agregue la fusión de lectura-modificación-escritura al optimizador de mirilla (como mínimo). Claro, es más trabajo, pero solo mira cuánto más trabajo es para todos lidiar con tipos tan extraños en lugares donde nunca aparecerán. Yuck
Restablece a Mónica
24

Estoy bastante seguro de que los sistemas VAX todavía están en uso. No admiten IEEE de punto flotante; ellos usan sus propios formatos. Alpha admite los formatos de punto flotante VAX e IEEE.

Las máquinas de vectores Cray, como la T90, también tienen su propio formato de punto flotante, aunque los sistemas Cray más nuevos usan IEEE. (El T90 que utilicé fue retirado hace algunos años; no sé si alguno todavía está en uso activo).

El T90 también tenía / tiene algunas representaciones interesantes para punteros y enteros. Una dirección nativa solo puede apuntar a una palabra de 64 bits. Los compiladores de C y C ++ tenían CHAR_BIT == 8 (necesario porque ejecutaba Unicos, un sabor de Unix, y tenían que interactuar con otros sistemas), pero una dirección nativa solo podía apuntar a una palabra de 64 bits. Todas las operaciones a nivel de byte se sintetizaron por el compilador, y una void*o char*almacenan un desplazamiento en el alto orden 3 bits de la palabra de bytes. Y creo que algunos tipos enteros tenían bits de relleno.

Los mainframes de IBM son otro ejemplo.

Por otro lado, estos sistemas particulares no necesariamente excluyen cambios al estándar del lenguaje. Cray no mostró ningún interés particular en actualizar su compilador de C a C99; presumiblemente lo mismo se aplica al compilador de C ++. Que podría ser razonable para apretar los requisitos para implementaciones alojadas, como requerir CHAR_BIT == 8, el formato de punto flotante IEEE, si no la semántica completos, y de complemento a 2 sin bits de relleno para los enteros con signo. Los sistemas antiguos podrían continuar admitiendo estándares de lenguaje anteriores (C90 no murió cuando salió C99), y los requisitos podrían ser más flexibles para implementaciones independientes (sistemas integrados) como DSP.

Por otro lado, puede haber buenas razones para que los sistemas futuros hagan cosas que hoy se considerarían exóticas.

Keith Thompson
fuente
66
Buen punto al final sobre cómo normas demasiado estrictas impiden la innovación. Cuando obtengamos computadoras cuánticas (u orgánicas) con estados trinarios, los requisitos de módulo de aritmética para los unsignedtipos integrales serán un gran problema, mientras que la aritmética con signo estará bien.
Ben Voigt
@BenVoigt ¿Por qué esa aritmética sin signo es un dolor? ¿No es posible el módulo 3 ^ n sumadores en esas computadoras?
phuclv
2
@ LưuVĩnhPhúc: Ese es exactamente el punto, con operaciones de hardware realizadas módulo 3 ** n, proporcionar tipos sin signo de C ++ cuyas operaciones se definen módulo 2 ** n será difícil.
Ben Voigt
2
Sé de un VAX 11/780 todavía en uso como host para un compilador cruzado dirigido a un sistema integrado especializado con una arquitectura patentada. Para mantener ese VAX en particular, los custodios se han acercado a los museos en busca de repuestos.
Peter
2
@Keith: técnicamente, el único obstáculo es pasar por un proceso para proporcionar evidencia que satisfaga los requisitos reglamentarios, ya que el sistema embebido objetivo es de alta criticidad. Sin embargo, hay un montón de obstáculos no técnicos (política organizacional, etc.) que hasta la fecha han sido insuperables. Actualmente, es más fácil montar un caso para asaltar museos que actualizar el host.
Peter
16

CHAR_BITS

Según el código fuente de gcc :

CHAR_BITson 16bits para arquitecturas 1750a , dsp16xx .
CHAR_BITson 24bits para la arquitectura dsp56k .
CHAR_BITson 32bits para la arquitectura c4x .

Puede encontrar más fácilmente haciendo:

find $GCC_SOURCE_TREE -type f | xargs grep "#define CHAR_TYPE_SIZE"

o

find $GCC_SOURCE_TREE -type f | xargs grep "#define BITS_PER_UNIT"

si CHAR_TYPE_SIZEse define adecuadamente

Cumplimiento IEEE 754

Si la arquitectura de destino no admite instrucciones de coma flotante, gcc puede generar software alternativo que no cumple con el estándar por defecto. -funsafe-math-optimizationsAdemás, se pueden usar opciones especiales (como bruja también deshabilita la preservación de signos para ceros).

ivaigult
fuente
3
votó por simplemente dirigir el OP para que mire la fuente de un compilador popular; Esta es la definición de RFTM en este caso, por lo que debería ser el primer lugar donde la gente mira.
underscore_d
9

La representación binaria IEEE 754 era poco común en las GPU hasta hace poco, ver Paranoia de punto flotante de GPU .

EDITAR: se ha planteado una pregunta en los comentarios sobre si el punto flotante de GPU es relevante para la programación informática habitual, sin relación con los gráficos. ¡Oh sí! La mayoría de las cosas de alto rendimiento calculadas industrialmente hoy en día se realizan en GPU; la lista incluye IA, minería de datos, redes neuronales, simulaciones físicas, pronóstico del tiempo y mucho más. Uno de los enlaces en los comentarios muestra por qué: un orden de magnitud de ventaja de coma flotante de las GPU.

Otra cosa que me gustaría agregar, que es más relevante para la pregunta de OP: ¿qué hicieron las personas hace 10-15 años cuando el punto flotante de GPU no era IEEE y cuando no había API como OpenCL o CUDA para programar GPU? ¡Lo creas o no, los primeros pioneros en informática de GPU lograron programar GPU sin una API para hacerlo ! Conocí a uno de ellos en mi empresa. Esto es lo que hizo: codificó los datos que necesitaba para calcular como una imagen con píxeles que representaban los valores en los que estaba trabajando, luego usó OpenGL para realizar las operaciones que necesitaba (como "desenfoque gaussiano" para representar una convolución con una distribución normal , etc.) y decodificó la imagen resultante nuevamente en una matriz de resultados. ¡Y esto todavía fue más rápido que usar CPU!

Cosas como esa es lo que llevó a NVidia a finalmente hacer que sus datos binarios internos sean compatibles con IEEE e introducir una API orientada a la computación en lugar de la manipulación de imágenes.

Miguel
fuente
¿Cómo son relevantes las GPU? (a) Esta página parece muy desactualizada. (b) Hasta el día de hoy no puede programar GPU en C: porque C admite cosas como funciones recursivas que, a mi leal saber y entender, las GPU no admiten. Así que ni siquiera puedes escribir un compilador si quisieras.
Yakov Galka
1
@ybungalobill, descargar el trabajo repetitivo a la GPU es actualmente el método preferido para los cálculos a gran escala . De hecho, actualmente estoy desarrollando uno en C ++. Afortunadamente, solo trabajamos con GPU NVidia CUDA que tienen una representación binaria de flotadores compatibles con IEEE 754.
Michael
No digo que las GPU no se usen para cálculos GP. Dije que realmente no se programan los núcleos en C, a pesar de la similitud de sintaxis. ¿Se puede ejecutar int f(int n) { return n <= 1 ? 1 : n * f(n-1); }en CUDA? Si no, las GPU no son relevantes para esta pregunta (que pregunta sobre los comités C y C ++).
Yakov Galka
66
@ybungalobill: varias respuestas a eso. Primero, CUDA admite C, C ++ y Fortran . Vea el mismo enlace para conocer la enorme ventaja de rendimiento de las GPU de 2048 hilos sobre su CPU típica de 8 hilos. En segundo lugar, es cierto, solo se admiten subconjuntos (aunque grandes) de esos lenguajes, incluida la falta de soporte apropiado para la recursión del modelo de programación CUDA (llamado "paralelismo dinámico") hasta CUDA 5.0. En tercer lugar, las recursiones generalmente se pueden reemplazar por bucles, lo cual es necesario para un rendimiento multiproceso de todos modos.
Michael