# Saselang — Annexe A — Matrice des conversions numériques **Version documentaire : 0.2.17. Statut : inventaire de conception Core destiné à devenir normatif après validation.** Cette annexe inventorie les conversions numériques Core sémantiquement distinctes sans créer d'alias ou de doublons inutiles. ## A.1. Répartition des responsabilités Les conversions numériques sont des capacités de l'API Core des primitives, pas des constructions grammaticales distinctes. ```text Bible langage / compilateur définit typage, contrats, faults, targets et lowering Core expose les membres numériques concrets ex. int32::toInt8(), float64::roundToFloat32() Annexe Core liste les opérations disponibles par paire de types Compilateur / Sase IR / backend valide et abaisse les opérations Core ``` Si les types source et destination sont supportés par un target, les conversions fondamentales non redondantes sont Core-required. Une implémentation logicielle conforme est admise lorsqu'une instruction matérielle n'existe pas. ## A.2. Règle de non-redondance Une variante n'existe que si elle apporte une sémantique observable différente de l'opération canonique déjà disponible pour la paire source/destination. Exemple : ```text int8 value = ...; int32 larger = value::toInt32(); ``` Toutes les valeurs `int8` sont exactement représentables dans `int32`; il n'existe donc pas de variantes inutiles `saturateToInt32()` ou `wrapToInt32()`. Pour `int32 -> int8`, les trois contrats suivants sont distincts : ```text toInt8() // exact, peut fault OutOfRange saturateToInt8() wrapToInt8() ``` Règle de composition : > Deux opérations ne sont fusionnées dans un même nom que si leur séparation en opérations Core successives modifierait la sémantique, perdrait de l'information ou empêcherait d'exprimer le même contrat. Ainsi : ```text value::floor()::toInt32() ``` rend inutile un alias `floorToInt32()` si les deux formes sont strictement équivalentes. ## A.3. Canal d'échec V1 Les anciennes variantes `try... -> Result` ne font plus partie de la matrice canonique uniquement pour transporter un échec de conversion. La conversion directe retourne la destination attendue et peut déclarer : ```text faults NumericConversionFault ``` lorsque sa précondition runtime n'est pas totale. `NumericConversionFault` est unchecked et capturable. Une API spécialisée peut toujours choisir explicitement `Result` si son domaine veut représenter l'échec comme une valeur normale, mais cela ne crée pas une seconde famille automatique `try...` dans le Core numérique. ## A.4. Nomenclature générale | Code | Famille | Contrat | |---|---|---| | `T` | `toTarget()` | Exacte et totale pour toutes les valeurs valides du type source. | | `E` | `toTarget()` | Exacte pour la valeur courante ; `faults NumericConversionFault` si impossible. | | `R` | `roundToTarget()` | Perte de précision explicitement acceptée ; totale pour cette paire. | | `FR` | `roundToTarget()` | Arrondi accepté ; peut fault si la valeur est hors du domaine destination. | | `S` | `saturateToTarget()` | Saturation explicite lorsqu'aucun arrondi supplémentaire n'est nécessaire. | | `SR` | `saturatingRoundToTarget()` | Arrondi canonique + saturation explicites. | | `W` | `wrapToTarget()` | Conversion entière modulo `2^N`. | | `—` | aucune | Même type ou opération sans sémantique distincte utile. | Aucune de ces opérations n'autorise une conversion implicite entre deux valeurs déjà typées. ## A.5. Flottants : hypothèses de représentation | Type | Précision significative `p` | Exposant maximal fini | |---|---:|---:| | `float16` | 11 bits | 15 | | `float32` | 24 bits | 127 | | `float64` | 53 bits | 1023 | | `float128` | 113 bits | 16383 | Les conversions avec arrondi utilisent la règle canonique **round to nearest, ties to even**. Cette règle ne dépend ni du linter, ni du profil, ni du backend. ## A.6. Entier -> entier Légende : ```text T toTarget() total E+S+W toTarget() faults OutOfRange saturateToTarget() wrapToTarget() ``` | Source \ Destination | int8 | int16 | int32 | int64 | int128 | int256 | uint8 | uint16 | uint32 | uint64 | uint128 | uint256 | |---|---|---|---|---|---|---|---|---|---|---|---|---| | int8 | — | T | T | T | T | T | E+S+W | E+S+W | E+S+W | E+S+W | E+S+W | E+S+W | | int16 | E+S+W | — | T | T | T | T | E+S+W | E+S+W | E+S+W | E+S+W | E+S+W | E+S+W | | int32 | E+S+W | E+S+W | — | T | T | T | E+S+W | E+S+W | E+S+W | E+S+W | E+S+W | E+S+W | | int64 | E+S+W | E+S+W | E+S+W | — | T | T | E+S+W | E+S+W | E+S+W | E+S+W | E+S+W | E+S+W | | int128 | E+S+W | E+S+W | E+S+W | E+S+W | — | T | E+S+W | E+S+W | E+S+W | E+S+W | E+S+W | E+S+W | | int256 | E+S+W | E+S+W | E+S+W | E+S+W | E+S+W | — | E+S+W | E+S+W | E+S+W | E+S+W | E+S+W | E+S+W | | uint8 | E+S+W | T | T | T | T | T | — | T | T | T | T | T | | uint16 | E+S+W | E+S+W | T | T | T | T | E+S+W | — | T | T | T | T | | uint32 | E+S+W | E+S+W | E+S+W | T | T | T | E+S+W | E+S+W | — | T | T | T | | uint64 | E+S+W | E+S+W | E+S+W | E+S+W | T | T | E+S+W | E+S+W | E+S+W | — | T | T | | uint128 | E+S+W | E+S+W | E+S+W | E+S+W | E+S+W | T | E+S+W | E+S+W | E+S+W | E+S+W | — | T | | uint256 | E+S+W | E+S+W | E+S+W | E+S+W | E+S+W | E+S+W | E+S+W | E+S+W | E+S+W | E+S+W | E+S+W | — | Règles : - domaine source entièrement inclus -> `to...` total ; - sinon `to...` reste exact mais peut produire `OutOfRange` ; - `saturateTo...` borne à `Target::Min` / `Target::Max`, avec `0` pour un négatif vers non signé ; - `wrapTo...` utilise une définition mathématique modulo `2^N` ; - aucun wrapping ni saturation n'est implicite. ## A.7. Entier -> flottant Légende : ```text T toFloatXX() total et exact E+R toFloatXX() exact, peut fault Inexact roundToFloatXX() total E+FR+SR toFloatXX() exact, peut fault Inexact/OutOfRange roundToFloatXX() peut fault OutOfRange saturatingRoundToFloatXX() total ``` | Source \ Destination | float16 | float32 | float64 | float128 | |---|---|---|---|---| | int8 | T | T | T | T | | int16 | E+R | T | T | T | | int32 | E+FR+SR | E+R | T | T | | int64 | E+FR+SR | E+R | E+R | T | | int128 | E+FR+SR | E+R | E+R | E+R | | int256 | E+FR+SR | E+FR+SR | E+R | E+R | | uint8 | T | T | T | T | | uint16 | E+FR+SR | T | T | T | | uint32 | E+FR+SR | E+R | T | T | | uint64 | E+FR+SR | E+R | E+R | T | | uint128 | E+FR+SR | E+FR+SR | E+R | E+R | | uint256 | E+FR+SR | E+FR+SR | E+R | E+R | Exemple : ```text int64 value = ...; float64 exact = value::toFloat64(); float64 approximated = value::roundToFloat64(); ``` La première opération exige l'exactitude et peut produire `NumericConversionFault::Inexact`; la seconde accepte explicitement la perte de précision. ## A.8. Flottant -> flottant Légende : ```text T toFloatXX() total et exact E+FR+SR toFloatXX() exact, peut fault roundToFloatXX() accepte l'arrondi, peut fault OutOfRange fini saturatingRoundToFloatXX() total ``` | Source \ Destination | float16 | float32 | float64 | float128 | |---|---|---|---|---| | float16 | — | T | T | T | | float32 | E+FR+SR | — | T | T | | float64 | E+FR+SR | E+FR+SR | — | T | | float128 | E+FR+SR | E+FR+SR | E+FR+SR | — | Règles : - l'élargissement de format utilise `toFloatXX()` total ; - la réduction exacte utilise `toFloatXX()` avec fault si nécessaire ; - `roundToFloatXX()` accepte la perte de précision mais pas un débordement fini ; - `saturatingRoundToFloatXX()` sature seulement les valeurs finies hors domaine fini ; - `NaN`, `+Infinity`, `-Infinity`, `+0` et `-0` restent des catégories valides ; - pour `NaN`, seule la propriété sémantique `isNaN(destination) == true` est garantie. ## A.9. Flottant -> entier : composition des politiques La conversion stricte canonique est : ```text toIntXX() toUintXX() ``` avec : ```text faults NumericConversionFault ``` lorsque la valeur peut être non finie, non entière ou hors plage. ### A.9.1. Politiques mathématiques séparées ```text floor() ceil() round() truncate() ``` restent des opérations sur le flottant. Elles se composent ensuite avec la conversion : ```text value::floor()::toInt32() value::ceil()::toInt32() value::round()::toInt32() value::truncate()::toInt32() ``` Aucun alias combiné n'est ajouté lorsqu'il serait strictement équivalent. ### A.9.2. Dépassement de domaine Pour chaque destination entière, le Core peut exposer : ```text toTarget() saturateToTarget() wrapToTarget() ``` | Opération | Préconditions hors plage | Politique de plage | |---|---|---| | `toTarget()` | valeur finie et mathématiquement entière | `OutOfRange` si hors plage | | `saturateToTarget()` | valeur finie et mathématiquement entière | borne à `Target::Min` / `Target::Max` | | `wrapToTarget()` | valeur finie et mathématiquement entière | modulo `2^N` | `NotFinite` et `NotIntegral` restent possibles pour les trois familles lorsqu'elles s'appliquent. Exemples : ```text value::floor()::saturateToInt32() value::round()::saturateToUint16() value::truncate()::wrapToInt8() value::ceil()::wrapToUint64() ``` ### A.9.3. Matrice flottant -> entier après élimination des doublons Légende : ```text C toTarget() uniquement CSW toTarget() saturateToTarget() wrapToTarget() ``` | Source \ Destination | int8 | int16 | int32 | int64 | int128 | int256 | uint8 | uint16 | uint32 | uint64 | uint128 | uint256 | |---|---|---|---|---|---|---|---|---|---|---|---|---| | float16 | CSW | CSW | C | C | C | C | CSW | CSW | CSW | CSW | CSW | CSW | | float32 | CSW | CSW | CSW | CSW | CSW | C | CSW | CSW | CSW | CSW | CSW | CSW | | float64 | CSW | CSW | CSW | CSW | CSW | CSW | CSW | CSW | CSW | CSW | CSW | CSW | | float128 | CSW | CSW | CSW | CSW | CSW | CSW | CSW | CSW | CSW | CSW | CSW | CSW | Cas particuliers : - `+0` et `-0` donnent zéro ; - `NaN` et les infinities produisent `NotFinite` ; - une valeur fractionnaire produit `NotIntegral` avant la politique de plage ; - vers un non signé, la saturation d'une valeur négative entière donne `0` ; - le wrapping s'applique à l'entier mathématique fini modulo `2^N`. ## A.10. `bitcast` reste hors de cette matrice `bitcast(value)` conserve les bits et change leur interprétation sous ses propres contraintes. Il ne constitue jamais une alternative implicite à `to...`, `round...`, `saturate...` ou `wrap...`. ## A.11. Typage contextuel des littéraux Le typage contextuel d'un littéral reste distinct de toute conversion de valeur déjà typée. ```text int32 a = 42; int8 small = ...; int32 b = small; // ERROR int32 c = small::toInt32(); // OK ``` ## A.12. `NumericConversionFault` ```text NumericConversionFault extends Fault ``` Codes sémantiques V1 : ```text NotFinite NotIntegral OutOfRange Inexact ``` Le fault reste minimal et ne transporte pas automatiquement la valeur source, les types source/destination, le backend, un timestamp ou un mode d'arrondi. ## A.13. État de l'annexe Principes largement figés : ```text non-redondance par paire composition plutôt qu'alias combinés Fault direct à la place des anciens try... purement mécaniques règles float -> integer règles NaN / infinities / signed zero NumericConversionFault Core-required pour les types supportés émulation logicielle lorsque raisonnable ``` Restent principalement à auditer lors de l'implémentation Core : 1. le listing mécanique exhaustif des membres concrets exposés par chaque primitive ; 2. les noms définitifs des constantes/membres Core associés ; 3. la représentation interne exacte des codes `NumericConversionFault` ; 4. les tests de conformité couvrant toutes les cellules de la matrice.