2015-12-15 1 views

Répondre

37

De N3337:

[basic.fundamental/8]: Il existe trois types de virgule flottante: float, double et long double. Le type double fournit au moins autant de précision que le flotteur, et le type long double fournit au moins autant de précision que le double. L'ensemble de valeurs du type float est un sous-ensemble de l'ensemble des valeurs du type double; l'ensemble des valeurs du type double est un sous-ensemble de l'ensemble des valeurs du type long double. La représentation en valeur des types à virgule flottante est définie par l'implémentation. Les types intégrants et flottants sont collectivement appelés types arithmétiques . Les spécialisations du modèle standard std :: numeric_limits (18.3) doivent spécifier le maximum et les valeurs minimales de chaque type arithmétique pour une implémentation.

Si vous voulez vérifier si votre application utilise IEEE-754, vous pouvez utiliser std::numeric_limits::is_iec559:

static_assert(std::numeric_limits<double>::is_iec559, 
       "This code requires IEEE-754 doubles"); 

Il y a un certain nombre d'autres traits d'aide dans ce domaine, comme has_infinity, quiet_NaN et more .

+1

Votre citation ne répond pas vraiment à la question. La question demande s'il existe des restrictions sur les formats de virgule flottante autorisés. Votre réponse montre que les formats à virgule flottante doivent être documentés par l'implémenteur. C'est lié mais pas vraiment la même chose. – hvd

+6

@hvd: Cela (l'implémenteur doit fournir la documentation) EST la seule restriction, à part les plages et opérations requises que la bibliothèque mathématique doit implémenter. –

+0

@hvd Je ne suis pas sûr de comprendre. Est-ce qu'une simple "ceci est la seule restriction" dans la réponse serait suffisante pour vous? – TartanLlama

3

L'idée de std::is_floating_point est de faire mieux fonctionner le code utilisateur d'origine différente. Techniquement, vous pouvez spécifier un int comme std::is_floating_point sans provoquer de comportement indéfini. Mais disons que vous avez une bibliothèque sur un modèle qui doit diviser à plusieurs reprises par T n. Pour accélérer les choses, la bibliothèque crée un T ni = 1/n et remplace la division par n par multiplication par ni. Cela fonctionne très bien pour les nombres à virgule flottante, mais échoue pour les entiers. Par conséquent, la bibliothèque ne fait correctement l'optimisation que si std::is_floating_point<T>::value == true. Si vous vous trouvez, le code fonctionne probablement du point de vue de la norme, mais est incorrect d'un point de vue logique. Donc, si vous écrivez une classe qui se comporte comme une plus grande float marquez-la comme std::is_floating_point, sinon ne le faites pas. Cela devrait vous permettre d'obtenir un code optimal et correct.

7

Aucune implémentation particulière n'est requise. La norme C++ n'en parle pas beaucoup. La norme C aborde un certain nombre de détails sur le modèle conceptuel supposé pour les nombres à virgule flottante, avec un signe, un exposant, un significant dans une base b, et ainsi de suite. Il, cependant, précise que cela est purement descriptive, et non une exigence sur la mise en œuvre (C11, note 21):

Le modèle à virgule flottante vise à préciser la description de chaque caractéristique et à virgule flottante ne nécessite pas que l'arithmétique en virgule flottante de l'implémentation soit identique.

Cela dit, bien que les détails peuvent varier, au moins désinvolture il me semble que la production (par exemple) une mise en œuvre conforme de double qui ne correspondait pas assez en étroite collaboration avec le modèle habituel (c.-à-un significand et exposant) serait difficile (ou du moins difficile à faire avec la performance compétitive, de toute façon). Cependant, il ne serait pas particulièrement difficile de le faire varier d'une autre manière, par exemple en réarrangeant l'ordre ou en utilisant une base différente. La définition de std::numeric_limits<T>::digits (et std::numeric_limits<T>::digits10) implique assez directement que ce qui est répertorié en tant que type à virgule flottante doit conserver (au moins approximativement) la même précision pour tous les nombres sur une plage assez étendue de grandeurs. De loin, la façon la plus évidente d'y parvenir est d'avoir un certain nombre de bits/chiffres consacrés à un significand, et un autre ensemble (séparé) de bits consacré à un exposant.

+1

Je pense que les définitions de 'numeric_limits :: digits' et' digits10' rendent difficile d'échapper à un signifiant quelque part là-bas (la façon dont la représentation de bits fonctionne est une autre affaire). Donc, à tout le moins, vous ne pouvez pas faire passer un type de largeur fixe à travers comme «double» et conforme. Je suspecte comme vous, qu'il est contraint d'être * point * flottant. Utiliser une base différente est explicitement couvert par 'radix' :-) –

+0

@SteveJessop: Ouais, c'était à peu près tout ce que je pensais aussi. –

+0

@SteveJessop Qu'est-ce qui vous empêche exactement de copier-coller 'int' pour presque toutes les propriétés de 'numeric_limits'? – Yakk

10

La norme C a une «annexe» (en C11 c'est l'annexe F) qui expose ce que signifie pour une implémentation de C être conforme à la norme CEI 60559, la norme successeur de l'IEEE 754. Une implémentation conforme à l'annexe F doit avoir des nombres à virgule flottante de représentation IEEE. Cependant, la mise en œuvre de cette annexe est facultative. la norme de base évite spécifiquement de parler de la représentation des nombres à virgule flottante.

Je ne sais pas s'il existe une annexe équivalente pour C++. Il n'apparaît pas dans N3337, mais cela pourrait simplement signifier qu'il est distribué séparément. L'existence de std::numeric_limits<floating-type>::is_iec559 indique que le comité C++ au moins a pensé à ce sujet, mais peut-être pas autant de détails que le comité C l'a fait. (Il est et a toujours été une honte que le standard C++ ne soit pas exprimé comme un ensemble de modifications au standard C.)