Il y avait déjà plusieurs articles sur Habré (
un ,
deux ,
deux et demi ) consacrés au nouveau format à virgule flottante Posit, dont les auteurs le présentent comme supérieur au flotteur standard IEEE 754 à tous égards. Le nouveau format a également trouvé des critiques (
un ,
deux ) qui affirment que les défauts de Posit l'emportent sur ses mérites. Mais que se passe-t-il si nous avons vraiment un nouveau format révolutionnaire, et la critique est simplement causée par l'envie et l'incompétence de ceux qui critiquent? Eh bien, la meilleure façon de le savoir est de prendre et de calculer soi-même.
Présentation
Les avantages du nouveau format sont démontrés par des exemples simples avec addition / multiplication de nombres d'un ordre similaire, ce qui se traduit par une précision supérieure d'un ou deux chiffres. Cependant, dans les calculs réels, plus / moins un bit de l'erreur d'une seule opération n'a pas d'importance, car nous le calculons avec une précision limitée de toute façon. L'
accumulation d' erreur à la suite de la séquence d'opérations est importante, lorsque, après un certain temps, les erreurs dans les chiffres inférieurs commencent à conduire à l'erreur dans les plus anciennes. C'est ce que nous allons essayer de vivre.
La préparation
Pour les tests, j'ai pris l'implémentation Posit avec un titre pathos
d'ici . Pour le compiler dans Visual Studio, nous avons dû ajouter la ligne #define CLZ (n) __lzcnt (n) dans le fichier util.h et remplacer 0.f / 0.f dans le fichier posit.cpp par std :: numeric_limits <float> :: quiet_NaN (). Soit dit en passant, les implémentations des fonctions mathématiques élémentaires (enfin, à l'exception de la racine) n'étaient pas non plus trouvées dans cette bibliothèque - c'est une autre raison de soupçonner que quelque chose n'allait pas.
Test 1. Multiplication de nombres complexes
La transformée de Fourier, calculée à l'aide d'une arithmétique complexe, est utilisée dans la mesure du possible. Au début, je voulais tester Posit sur la transformée de Fourier; mais comme sa précision dépend largement de l'implémentation, pour des tests corrects, vous devrez considérer tous les algorithmes de base, ce qui prend un peu de temps; par conséquent, vous pouvez commencer par une opération plus simple - la multiplication de nombres complexes.
Si nous prenons un certain vecteur et le faisons pivoter 360 fois de 1 °, à la fin, nous devrions obtenir le même vecteur d'origine. En fait, le résultat sera légèrement différent en raison de l'accumulation d'erreurs - et plus le nombre de tours est grand, plus l'erreur est grande. Donc, en utilisant ce code simple
complex<T> rot(cos(a), sin(a)); complex<T> vec(length, 0); for (long i = 0; i < count; i++) { vec *= rot; } cout << "error: " << stdev(vec.real() - length, vec.imag()) << endl;
nous faisons pivoter le vecteur avec différents types de données et nous considérons l'erreur comme l'écart carré moyen du vecteur résultant par rapport à l'original (qui peut également être interprété comme la longueur du vecteur de différence).
Tout d'abord, prenez le vecteur unitaire comme le plus favorable de Posit:
Il n'y a pas encore de leader évident ici - l'avantage est deux fois supérieur à l'un ou à l'autre. Augmentez la longueur du vecteur pivoté à 1000:
Les valeurs d'erreur sont presque égales. Allez-y - 1000000:
Ici, Posit est déjà en retard avec confiance, et la double erreur commence à se glisser dans le flotteur. Prenons une longueur encore plus longue - 10
10 pour apprécier pleinement les avantages des formats à virgule flottante:
Voici la chose la plus intéressante au début, à 4 itérations - lorsque le flottant donne une erreur proportionnelle au double, et Posit a déjà un résultat complètement incorrect.
Test 2. Calcul d'un polynôme rationnel
Puisqu'il n'y avait pas de fonctions mathématiques dans la bibliothèque d'origine, nous allons essayer de faire quelque chose par nous-mêmes. De nombreuses fonctions sont mal approximées en se développant dans une série de Taylor, et elles sont plus commodes à calculer par approximation par un polynôme rationnel. Cette approximation peut être obtenue de différentes manières, y compris purement analytique - par l'
approximation Padé . Nous le prendrons par ailleurs pour des tests avec des coefficients suffisamment importants pour qu'ils subissent également des arrondis avant calcul.
Utilisation de Wolfram Mathematica et de la commande PadeApproximant [Sin [x], {x, 0, {11, 11}}]
nous obtenons un tel polynôme rationnel pour approximer le sinus, ce qui fournit une double précision dans la plage d'environ -2 à 2:
\ frac {- \ frac {481959816488503 x ^ {11}} {363275871831577908403200} + \ frac {23704595077729 x ^ 9} {42339845201815607040} - \ frac {2933434889971 x ^ 7} {336030517476070}} 3333 } {617703157122660} - \ frac {109061004303 x ^ 3} {722459832892} + x} {\ frac {37291724011 x ^ {10}} {11008359752472057830400} + \ frac {3924840709 x ^ 8} {2016183104848362240} x ^ 6} {168015258737363520} + \ frac {1679739379 x ^ 4} {13726736824948} + \ frac {34046903537 x ^ 2} {2167379498676} +1}
Le schéma de Horner est généralement utilisé directement pour les calculs afin d'économiser sur les calculs. Dans notre cas (en utilisant HornerForm), cela ressemblera à
template< typename T > T padesin(T x) { T xx = x*x; return (x*(T(363275871831577908403200.) + xx*(-T(54839355237791393068800.) + xx*(T(2120649063015013090560.) + xx*(-T(31712777908498486800.) + xx*(T(203385425766914820.) - T(481959816488503.) * xx)))))) / (T(363275871831577908403200.) + xx*(T(5706623400804924998400.) + xx*(T(44454031219351353600.) + xx* (T(219578286347980560.) + xx*(T(707177798947620.) + T(1230626892363.) * xx))))); }
Voyons voir:
Comme vous pouvez le voir, la situation avec Posit ici semble déplorable - à peine deux numéros significatifs sont composés.
Conclusion
Malheureusement, un miracle ne s'est pas produit et la révolution est annulée. L'avantage de Posit démontré sur des calculs simples n'est rien de plus qu'une astuce, dont le prix est une diminution catastrophique de la précision dans les calculs réels "lourds". La seule raison pour laquelle il est logique d'utiliser Posit au lieu du flotteur IEEE 754 ou du point fixe est d'ordre religieux. L'utilisation du format magique, dont la précision est assurée par la sainte foi de ses créateurs, peut apporter de nombreuses merveilles à vos programmes!
Code source PS
pour vérification et critique .
PPS
Suite .