Je sais que les normes C et C ++ laissent de nombreux aspects de l'implémentation du langage définis simplement parce que s'il existe une architecture avec d'autres caractéristiques, il serait très difficile, voire impossible, d'écrire un compilateur conforme aux normes.
Je sais qu'il y a 40 ans, tout ordinateur avait sa propre spécification. Cependant, je ne connais aucune architecture utilisée aujourd'hui où:
CHAR_BIT != 8
signed
n'est pas un complément à deux (j'ai entendu dire que Java avait des problèmes avec celui-ci).- La virgule flottante n'est pas conforme à la norme IEEE 754 (Edit: je voulais dire "pas dans l'encodage binaire IEEE 754").
La raison pour laquelle je pose la question est que j'explique souvent aux gens qu'il est bon que C ++ n'impose aucun autre aspect de bas niveau comme les types de taille fixe † . C'est bien car contrairement aux `` autres langages '', cela rend votre code portable lorsqu'il est utilisé correctement (Edit: parce qu'il peut être porté sur plus d'architectures sans nécessiter d'émulation d'aspects de bas niveau de la machine, comme par exemple l'arithmétique du complément à deux sur l'architecture signe + magnitude) . Mais je me sens mal de ne pouvoir désigner moi-même aucune architecture spécifique.
La question est donc: quelles architectures présentent les propriétés ci-dessus?
† uint*_t
s sont facultatifs.
la source
Réponses:
Jetez un œil à celui-ci
Serveurs Unisys ClearPath Dorado
offrant une rétrocompatibilité pour les personnes qui n'ont pas encore migré tous leurs logiciels Univac.
Points clés:
CHAR_BIT == 9
Je ne sais pas s'ils proposent un compilateur C ++, mais ils le pourraient .
Et maintenant, un lien vers une édition récente de leur manuel C est apparu:
Manuel de référence de programmation du compilateur Unisys C
La section 4.5 a un tableau des types de données avec 9, 18, 36 et 72 bits.
la source
char*
etvoid*
doit être de la même taille et suffisamment grand pour contenir n'importe quel autre pointeur. Le reste dépend de la mise en œuvre.sizeof(int*) == 2
, mais les pointeurs éloignés avaient également un sélecteur 16 bits, doncsizeof(void*) == 4
.sizeof(int*) != sizeof(char*)
ici: les deux sont 36 bits. Mais le sélecteur d'octets dans lechar*
est sur les bits de poids fort et est ignoré dansint*
. (J'ai utilisé d'autres machines, cependant, où `sizeof (char *)> sizeof (int *).)void*
) avaient toujours la même taille. (Bien sûr, vous ne pouvez pas convertir un pointeur de fonction envoid*
, car ilvoid*
peut être plus petit. Mais selon la norme, vous ne pouvez pas non plus le faire aujourd'hui.)Aucune de vos hypothèses ne vaut pour les mainframes. Pour commencer, je ne connais pas de mainframe qui utilise IEEE 754: IBM utilise la base 16 en virgule flottante, et les deux mainframes Unisys utilisent la base 8. Les machines Unisys sont un peu spéciales à bien d'autres égards: Bo a mentionné le 2200 architecture, mais l'architecture MPS est encore plus étrange: mots balisés de 48 bits. (Que le mot soit un pointeur ou non dépend d'un peu du mot.) Et les représentations numériques sont conçues pour qu'il n'y ait pas de réelle distinction entre l'arithmétique à virgule flottante et intégrale: la virgule flottante est en base 8; il ne nécessite pas de normalisation, et contrairement à tous les autres points flottants que j'ai vus, il place la décimale à droite de la mantisse, plutôt qu'à gauche, et utilise une magnitude signée pour l'exposant (en plus de la mantisse). Avec les résultats qu'une valeur à virgule flottante intégrale a (ou peut avoir) exactement la même représentation en bits qu'un entier de magnitude signé. Et il n'y a pas d'instructions arithmétiques à virgule flottante: si les exposants des deux valeurs sont tous les deux 0, l'instruction fait de l'arithmétique intégrale, sinon, elle fait de l'arithmétique à virgule flottante. (Une continuation de la philosophie de marquage dans l'architecture.) Ce qui signifie que tout
int
peut occuper 48 bits, 8 d'entre eux doivent être 0 ou la valeur ne sera pas traitée comme un entier.la source
La conformité totale IEEE 754 est rare dans les implémentations en virgule flottante. Et affaiblir la spécification à cet égard permet de nombreuses optimisations.
Par exemple, le support subnorm diffère entre x87 et SSE.
Les optimisations comme la fusion d'une multiplication et d'une addition qui étaient séparées dans le code source modifient légèrement les résultats aussi, mais c'est une belle optimisation sur certaines architectures.
Ou sur x86, la conformité IEEE stricte peut nécessiter la définition de certains indicateurs ou des transferts supplémentaires entre les registres à virgule flottante et la mémoire normale pour le forcer à utiliser le type à virgule flottante spécifié au lieu de ses flottants internes de 80 bits.
Et certaines plates-formes n'ont aucun flotteur matériel et doivent donc les émuler dans le logiciel. Et certaines des exigences de la norme IEEE 754 peuvent être coûteuses à implémenter dans les logiciels. En particulier, les règles d'arrondi pourraient poser problème.
Ma conclusion est que vous n'avez pas besoin d'architectures exotiques pour entrer dans des situations où vous ne voulez pas toujours garantir une conformité IEEE stricte. Pour cette raison, peu de langages de programmation garantissent une stricte conformité IEEE.
la source
long double
aurait pu être un type utile et durable, car le seul vrai problème avec lui était qu'il fonctionne mal avecprintf
. Le fait que le double étendu stocke le premier 1 accélère explicitement les calculs sur les systèmes non FPU et éliminerait également le besoin de traitement spécial des dénormalités dans tout contexte autre que les conversions vers / à partir d'autres types. Dommage que C aitprintf
tout gâché.J'ai trouvé ce lien répertoriant certains systèmes où
CHAR_BIT != 8
. Ils comprennentEt bien sûr, il y a une question sur Stack Overflow: quelles plates-formes ont autre chose que le caractère 8 bits
En ce qui concerne les systèmes non complémentaires à deux, il y a une lecture intéressante sur comp.lang.c ++. Modérée . En résumé: il existe des plates-formes ayant un complément ou une représentation de signe et de grandeur.
la source
CHAR_BIT=32
, et Texas Instruments DSP de TMS32F28xx aCHAR_BIT=16
. GCC 3.2 pour PDP-10 aCHAR_BIT=9
. Je pense que S / 360 peut aussi avoir un caractère non 8 bits.CHAR_BITS
soit un duplicata partiel.Je suis assez sûr que les systèmes VAX sont toujours utilisés. Ils ne prennent pas en charge la virgule flottante IEEE; ils utilisent leurs propres formats. Alpha prend en charge les formats à virgule flottante VAX et IEEE.
Les machines vectorielles Cray, comme le T90, ont également leur propre format à virgule flottante, bien que les nouveaux systèmes Cray utilisent IEEE. (Le T90 que j'ai utilisé a été mis hors service il y a quelques années; je ne sais pas s'il y en a encore en cours d'utilisation.)
Le T90 avait également des représentations intéressantes pour les pointeurs et les entiers. Une adresse native ne peut pointer que sur un mot de 64 bits. Les compilateurs C et C ++ avaient CHAR_BIT == 8 (nécessaire car il exécutait Unicos, une version d'Unix, et devait interagir avec d'autres systèmes), mais une adresse native ne pouvait pointer que sur un mot de 64 bits. Toutes les opérations de niveau octet ont été synthétisées par le compilateur, et a
void*
ouchar*
stocké un décalage d'octet dans les 3 bits de poids fort du mot. Et je pense que certains types entiers avaient des bits de remplissage.Les mainframes IBM sont un autre exemple.
D'un autre côté, ces systèmes particuliers ne doivent pas nécessairement empêcher des modifications de la norme linguistique. Cray n'a montré aucun intérêt particulier pour la mise à niveau de son compilateur C vers C99; probablement la même chose appliquée au compilateur C ++. Il peut être raisonnable de resserrer les exigences pour les implémentations hébergées, comme exiger CHAR_BIT == 8, virgule flottante au format IEEE sinon la sémantique complète, et complément à 2 sans bits de remplissage pour les entiers signés. Les anciens systèmes pourraient continuer à prendre en charge les normes de langage antérieures (C90 n'est pas mort lorsque C99 est sorti), et les exigences pourraient être plus lâches pour les implémentations autonomes (systèmes embarqués) tels que les DSP.
D'un autre côté, il pourrait y avoir de bonnes raisons pour que les futurs systèmes fassent des choses qui seraient aujourd'hui considérées comme exotiques.
la source
unsigned
les types intégraux seront une douleur majeure, tandis que l'arithmétique signée sera très bien.CHAR_BITS
Selon gcc code source :
CHAR_BIT
est des16
bits pour les architectures 1750a , dsp16xx .CHAR_BIT
est des24
bits pour l' architecture dsp56k .CHAR_BIT
est des32
bits pour c4x architecture .Vous pouvez facilement en trouver plus en faisant:
ou
si
CHAR_TYPE_SIZE
est correctement défini.Conformité IEEE 754
Si l'architecture cible ne prend pas en charge les instructions en virgule flottante, gcc peut générer un logiciel de secours qui n'est pas conforme à la norme par défaut. De plus, des options spéciales (comme la
-funsafe-math-optimizations
sorcière désactive également la préservation des signes pour les zéros) peuvent être utilisées.la source
La représentation binaire IEEE 754 était rare sur les GPU jusqu'à récemment, voir GPU Floating-Point Paranoia .
EDIT: une question a été soulevée dans les commentaires si la virgule flottante GPU est pertinente pour la programmation informatique habituelle, sans rapport avec les graphiques. Putain, oui! La plupart des éléments de haute performance calculés industriellement aujourd'hui se font sur des GPU; la liste comprend l'IA, l'exploration de données, les réseaux neuronaux, les simulations physiques, les prévisions météorologiques et bien plus encore. L'un des liens dans les commentaires montre pourquoi: un ordre de grandeur avantage en virgule flottante d' des GPU.
Une autre chose que je voudrais ajouter, qui est plus pertinente à la question OP: qu'ont fait les gens il y a 10-15 ans quand la virgule flottante GPU n'était pas IEEE et quand il n'y avait pas d'API comme OpenCL ou CUDA d'aujourd'hui pour programmer les GPU? Croyez-le ou non, les premiers pionniers de l'informatique GPU ont réussi à programmer des GPU sans API pour le faire ! J'en ai rencontré un dans ma société. Voici ce qu'il a fait: il a encodé les données dont il avait besoin pour calculer comme une image avec des pixels représentant les valeurs sur lesquelles il travaillait, puis a utilisé OpenGL pour effectuer les opérations dont il avait besoin (comme le "flou gaussien" pour représenter une convolution avec une distribution normale , etc.) et a décodé l'image résultante en un tableau de résultats. Et c'était encore plus rapide que d'utiliser le processeur!
C'est ce qui a poussé NVidia à rendre enfin ses données binaires internes compatibles avec IEEE et à introduire une API orientée sur le calcul plutôt que sur la manipulation d'images.
la source
int f(int n) { return n <= 1 ? 1 : n * f(n-1); }
dans CUDA? Si non, les GPU ne sont pas pertinents pour cette question (qui concerne les comités C et C ++).