Conversation
…n one interval only
…[0.5, 1] in [0, +oo]
Owner
Author
|
Décidé le 6 octobre, sur les questions ouvertes, à reporter dans
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Point R de
TODO.md: la sortie anticipée dehausdorff()quand une borne n'est infinie que d'un côté, et unTEST_EQd'atanh_relà borne infinie (anciens 50 et 7).R.50 :
hausdorff()à borne infinieProblème. Depuis #41 (point 10),
hausdorff()calcule toutes ses distances par une seule formule, après la vérification du sens d'arrondi (GAOL_RND_ENTER()) :max(d(a, c), d(b, e)), avecd(x, y) = 0six == y. Le cas d'une borne infinie dans un seul des deux intervalles, qui vaut +oo, paie donc la vérification et les différences : de 10 à 12 ns, contre 2 à 4 ns s'il sort d'emblée (mesures ci-dessous). GAOL 4 rendait +oo d'emblée pour toute borne infinie.Correction (décidée le 3 octobre). Dans
gaol/gaol_interval_sse.cppetgaol/gaol_interval_fpu.cpp, après le test du vide et avantGAOL_RND_ENTER():inf - x, et le maximum avec l'autre côté reste +oo. Deux bornes infinies égales passent toujours par la formule et sont à distance 0 :hausdorff([1, +oo], [2, +oo])vaut 1. La phrase du commentaire de la formule sur ce cas, qu'elle ne voit plus, est retirée.GAOL_RND_BARRIER()force leur relecture ; avec Visual C++, c'est/fp:strictqui garde les comparaisons après l'écriture du registre de contrôle.doc/using.mdet le manuel ajoutent ce test à celui du vide, parmi les comparaisons faites avant la vérification.FE_INVALIDn'est levée dans aucun des 7 cas à borne infinie essayés ; la sortie anticipée ne lève pas non plus l'inexact, que la base levait.GAOL_PRESERVE_ROUNDING, la sortie anticipée laisse le sens d'arrondi tel qu'elle l'a trouvé, ce quetests/rounding_direction.cppadmet (« unchanged or upward »).std::fabs(x) == GAOL_INFINITYplutôt questd::isinf(x), sur la remarque du relecteur : c'est une comparaison sur tout compilateur. Avec l'UCRT de Visual C++,std::isinf()pourrait être un appel de fonction (_dtest()), comme l'étaient les comparaisons silencieuses de<cmath>(Point D (24 et 62) : plus d'exception flottante parasite, et leur documentation #83) : je ne l'ai pas vérifié ici.|au lieu de||) a été mesurée : elle n'est pas plus rapide.Mesures. Le banc fait la médiane de 5 mesures sur 1024 paires, en ns par appel (Intel i7-1185G7, Release, banc en
-O2, liens avec le GAOL installé). Le tableau donne le minimum de 10 passes alternant base et branche, pour l'écriture finale. Deux séries faites avec la première écriture (std::isinf()) avaient donné les mêmes chiffres l'une que l'autre à 0,1 ns près, et des chiffres à 1 ns au plus de ceux-ci (sur des bornes finies en SSE2 : 10,38 ns avecstd::isinf(), 11,36 avecstd::fabs()).[a, +oo],[c, d][-oo, b],[c, d][a, +oo],[c, +oo]Tests. Le comportement ne change pas : la sortie anticipée est couverte par
hausdorff_of_infinite_bounds()(tests/other_functions.cpp, 1225 paires de bornes dans {-oo, -2, -1, -0, 0, 1, 2, +oo}, contre des distances exactes) et par les vérifications de GAOL 4 danstests/interval_functions.cpp. Pour montrer qu'ils la protègent, deux mutants de la sortie anticipée, en SSE2 et en FPU :other_functions, 12 dansinterval_functions;other_functions, 3 dansinterval_functions;Ne tester qu'un des deux côtés est un mutant équivalent : le résultat est le même, seul le temps change.
R.7 :
atanh_relà borne infinietests/reverse_mappings.cppvérifiaitatanh_rel([0.5, 1], [0, 100]), où l'intersection avec un I borné cache la borne +oo de la préimage. Depuis #41,TEST_EQ(qui compare parhausdorff() <= 1e-8) peut comparer deux bornes infinies égales. Les vérifications ajoutées :TEST_EQ(atanh_rel([0.5, 1], [0, +oo]), [atanh(0.5), +oo]);TEST_EQ(atanh_rel([-1, -0.5], [-oo, 0]), [-oo, -atanh(0.5)]).La valeur de référence, 0.5493061443340548457, vient de mpmath à 2000 bits.
doc/tests.mdle dit dans l'entrée des tests de GAOL 4.Dents. Avec un
atanh()modifié pour borner la préimage par ±MAX au lieu de ±oo aux extrémités ±1, en SSE2 et en FPU :[0x1.193ea7aad030ap-1, 0x1.fffffffffffffp+1023]contre[0x1.193ea7aad030bp-1, inf]) ;reverse_mappings.cppdeconfigure-cleanpasse (584 vérifications, aucun échec) ;elementaryvoit lui aussi 6 échecs, suratanh()elle-même.L'autre moitié de R.7,
atanh([1])etatanh([-1])dansdoc/compare/special_cases.md, est laissée au point 33, comme décidé le 3 octobre.Pour
doc/differences.mdetChangeLog(pull request de synthèse)doc/differences.md, dans la puce dehausdorff(), celle de #41 qui sera fusionnée avec la puce de la l. 288 :ChangeLog:Relecture
Un relecteur indépendant, sans le contexte de ce travail, a relu la branche avec
process.md. Verdict : approuvée avec remarques, aucun point bloquant.Ce qu'il a vérifié (hors de l'arbre) :
hausdorff()sur toutes les paires de 66 intervalles (±0, ±3·2^-1074, ±1, 2, ±MAX, ±oo), dans les 4 sens d'arrondi et les 4 états de MXCSR (aucun mode, FTZ, DAZ, les deux), soit 69 696 résultats : identiques entre base et branche, avec GCC et Clang, en FPU et avecGAOL_PRESERVE_ROUNDING.FE_INVALIDsur des bornes infinies.-O3).other_functions,interval_functions,reverse_mappingsetrounding_directionpassent en SSE2, en FPU et avecGAOL_PRESERVE_ROUNDING, et compilent avec-Werror.atanh()sont attrapés.Ses remarques, toutes corrigées :
GAOL_RND_BARRIER()et à/fp:strict;std::isinf(), peut-être un appel avec Visual C++, remplacé parstd::fabs(x) == GAOL_INFINITY;doc/using.mdpour s'accorder au manuel, « a bounded I », «atanh_rel(J, I)».Sa dernière remarque est reportée aux questions ouvertes.
Vérifié en local
Sur le code final :
-DGAOL_SIMD=OFF) et Clang 18 : 56 tests réussis sur 56 dans chacun (intervalfetinterval2fsautés par construction).-Wall -WextraavecCMAKE_COMPILE_WARNING_AS_ERROR=ON, GCC 9.4 et Clang 18 : aucun avertissement, 56 sur 56.GAOL_PRESERVE_ROUNDING=ON, GCC SSE2 et Clang 18 FPU : 40 tests réussis sur 40 dans chacun.make distcleanrend l'arbre tel que git l'a.pdflatex, 129 pages, aucune erreur. Pas de nouvel « Overfull » : le seul était déjà dans la base, c'est celui que le point Y doit corriger, aux l. 525-529 degaol.texaujourd'hui.check_branch: OK.Non vérifiable ici : Windows (Visual C++, où
GAOL_RND_BARRIER()est vide et où le coût destd::fabs()n'est pas mesuré), MinGW-w64, macOS, ARM, POWER, s390x, et les processeurs sans FMA.Dépendances
Aucune.
Questions ouvertes
doc/using.md(l. 445, « Each operation of GAOL sets the rounding direction upward when it is not, and leaves it upward ») et le manuel ne disent pas que les opérations qui rendent avant leur vérification laissent le sens d'arrondi tel qu'elles l'ont trouvé : celles qui ont un opérande vide, avant ce changement, et maintenanthausdorff()à borne infinie d'un seul côté. Seul le paragraphe sur les modes flush-to-zero en parle. Je n'y ai pas touché.J.right() == -1.0d'atanh()(gaol/gaol_interval.cpp) ne fait échouer aucun test si on la retire :atanh([-1]),atanh([-5, -1])etatanh([-oo, -1])sont vides de toute façon,interval(-oo, -oo)l'étant. Un test ne la protégerait que si cette règle du constructeur changeait. Je n'y ai pas touché.atanh_rel()vérifie le sens d'arrondi puis appelleatanh(), qui le vérifie à nouveau, comme les cas que relève le point B.2. Je n'y ai pas touché.