Skip to content

Test du chemin précis de cos : 45 arguments contre mpmath, et les outils de contrôle du port - #212

Merged
Jordan08 merged 4 commits into
configure-cleanfrom
cos-accurate-path-test
Oct 28, 2026
Merged

Jordan08 merged 4 commits into
configure-cleanfrom
cos-accurate-path-test

Conversation

@Jordan08

Copy link
Copy Markdown
Owner

Suite de l'import de CORE-MATH 0b2ae6d1 (27 octobre, commits cb731c0 et 2927cfe poussés directement sur configure-clean à la demande du mainteneur) : l'amont a réécrit cos.c d'après le modèle de sin.c, et GAOL le porte sur gaol_u128 (3rd/README.md). Le reste de tests/core_math.cpp compare CORE-MATH à lui-même et ne peut pas voir une faute de ce port ; seule sin_accurate_path() le contrôlait, pour sin. Cette pull request ajoute le test jumeau pour cos, avec des valeurs de référence indépendantes.

Le test

cos_accurate_path() (tests/core_math.cpp) prend 45 arguments qui passent par le chemin précis de cos.c (cos_large_accurate()) dans l'arrondi vers le haut, celui où GAOL calcule. Pour chacun :

  • gaol_cr_cos(x) dans les quatre sens (au plus près, vers le haut, vers le bas, vers zéro) doit donner les arrondis de cos(x) calculés à part avec mpmath à 4 000 bits ;
  • cos(interval(x)) doit être [RD, RU], les bornes les plus serrées.

Les arguments sont choisis pour atteindre les branches du chemin : la réduction de l'argument qui arrondit k vers le haut ou non, l'indice i1 de t1 = i1 π/64 sous 32, égal à 32 et au-dessus, les trois façons de combiner cos(z) cos(r) et sin(z) sin(r) (somme, différence, différence avec changement de signe, qui n'arrive que près d'un multiple impair de π/2), chacune des 17 plages d'exposants de la table de 1/(2π) au-delà de 2^31, et les quatre arguments que exceptions() arrondit à part, avec leurs deux signes. Une copie instrumentée de cos.c (compteurs dans cos_large_accurate()) a servi à les trouver : tests/tools/cos/README.md dit comment.

Mesures : 0,57 % des arguments de 2^-13 à 2^31 prennent ce chemin dans chacun des quatre arrondis (11 377 sur 2 millions dans l'arrondi vers le haut), tous ceux au-delà de 2^31 aussi.

Outils (tests/tools/cos/)

  • accurate_values.py : recalcule avec mpmath (4 000 bits) et des rationnels exacts les quatre arrondis de cos(x) pour chaque ligne de la table et les compare (code de sortie 1 sinon) ; avec --rows il écrit les lignes d'arguments nouveaux. Il a des dents : un chiffre changé dans une ligne est signalé.
  • mutate.py : met une erreur à la fois dans une ligne de cos.c qui porte /* GAOL */ et relance le test.
  • un README.md, et deux lignes dans doc/tools.md.

Dents du test

17 erreurs mises une à une dans cos.c (le facteur 8 de r, le + 5 des exceptions, une somme devenue différence, une comparaison inversée, le comptage de zéros de u128_tod(), un décalage de 64 devenu 63, les moitiés de gaol_u128_make(V0, V1) échangées, le mot V2 pris dans _T[i+2], etc. : la liste est dans mutate.py et le README), plus l'échange des moitiés de la macro U128 pour -DGAOL_U128_EMULATION=ON. Avec le type natif et avec les moitiés forcées, le test échoue pour 15 des 17 (et pour l'échange des moitiés de U128). Les deux qui passent :

  • le masque de k + 1 : k n'est lu que par ses bits 0 à 12, le changement est équivalent ;
  • le + 1 de mask + 1 : le reste change de 2^-128, et 2,4 milliards d'appels de cr_cos() comparés au fichier amont (6·10^8 arguments, quatre arrondis) n'ont pas montré une différence.

Deux arguments entre 2^30 et 2^31, près d'un multiple impair de π/2, ont été ajoutés après qu'une erreur (le mot V2 pris dans le mauvais mot de la table) n'avait été vue par aucun autre. Limite : le test voit une faute qui déplace un résultat de plus de 2^-70 environ en relatif ; ses seuls arguments difficiles à arrondir sont ceux de exceptions(), dont k et neg sont nuls.

Pour doc/differences.md et ChangeLog (pull request de synthèse)

Rien : un test et ses outils.

Relecture

Un relecteur indépendant (sous-agent, sans mon contexte) n'a trouvé aucun point bloquant. Il a :

  • recalculé les 45 lignes avec mpmath à 3 000 et à 5 000 bits, avec son propre arrondi : 0 écart, et son script détecte un chiffre changé ;
  • instrumenté une copie de cos.c : les 45 arguments prennent le chemin précis en arrondi vers le haut, i parcourt -1 à 16, neg prend ses deux valeurs, i1 est sous 32, égal à 32 et au-dessus, les trois branches de combinaison arrivent, les 8 lignes d'exceptions passent par exceptions() ;
  • vérifié que les 38 lignes modifiées de cos.c par rapport à l'amont portent /* GAOL */ et ne sont que des traductions d'opérateurs ;
  • mis 37 erreurs une à une : le test en trouve 29, et les 8 autres sont sous 2^-70 environ ou équivalentes (signes de termes de haut degré des polynômes, neg toujours nul, mask + 0 ou mask + 2, un k | 1<<20) ; sur 5 d'entre elles, 10^8 arguments tirés dans les quatre arrondis n'ont pas montré de différence.

Corrigé à sa demande : le texte de 3rd/README.md (« 15 sur 17 » n'était pas vérifiable : la liste et la méthode sont maintenant dans tests/tools/cos/, et la limite de 2^-70 est dite), le script qui recalcule les valeurs (absent : ajouté), le commentaire de i1, la mention que les lignes d'exceptions sont de 2^-23 à 2^-20 et passent par le chemin précis dans les trois arrondis dirigés seulement, et la phrase de doc/tests.md. Il n'a pas pu compiler les sources amont (refusé par son bac à sable) : je l'ai fait moi-même, avec -O2 -frounding-math -ffp-contract=off, et elles donnent les 45 × 4 valeurs de mpmath.

Vérifié en local

core_math (2 176 436 vérifications, 0 échec, les 45 × 2 de cos comprises) avec GCC 15.2 SSE2 en -Wall -Wextra -Werror, avec les moitiés forcées (-DGAOL_U128_EMULATION=ON), en FPU (-DGAOL_SIMD=OFF), avec Clang 18, en Debug avec ASan et UBSan (type natif et moitiés), sous LC_ALL=fr_FR.UTF-8, et sur Debian i386 (GCC 14.2, où le type 128 bits est les deux moitiés, par défaut et forcées). Avec gcov, toutes les lignes /* GAOL */ de cos.c s'exécutent dans core_math. Aucun fichier de build ne change (le test est dans un programme existant), donc ni autotools ni meson n'ont été relancés.

Non vérifiable ici : Visual C++ (/W4 /WX), clang-cl, MinGW-w64, MSYS2, macOS, ARM 32 bits, s390x, POWER, RISC-V et GCC 9 : seule la CI les couvre.

Dépendances

Aucune. Elle touche tests/core_math.cpp comme #206 (le déplacement du test de direction de CORE-MATH) : un conflit, s'il y en a un, se résout sans difficulté (fonctions différentes).

Questions ouvertes

  • Voulez-vous des arguments difficiles à arrondir pour cos (le fichier cos.wc des pires cas de l'amont n'est pas dans l'arbre) afin de voir aussi les fautes sous 2^-70 ? Ce serait une autre pull request.

@Jordan08
Jordan08 merged commit 17ad8fe into configure-clean Oct 28, 2026
221 checks passed
@Jordan08
Jordan08 deleted the cos-accurate-path-test branch October 28, 2026 08:51
Jordan08 added a commit that referenced this pull request Oct 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant