12 KiB
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.
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 :
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 :
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 :
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<T,NumericConversionError> 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 :
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 :
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 produireOutOfRange; saturateTo...borne àTarget::Min/Target::Max, avec0pour un négatif vers non signé ;wrapTo...utilise une définition mathématique modulo2^N;- aucun wrapping ni saturation n'est implicite.
A.7. Entier -> flottant
Légende :
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 :
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 :
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,+0et-0restent des catégories valides ;- pour
NaN, seule la propriété sémantiqueisNaN(destination) == trueest garantie.
A.9. Flottant -> entier : composition des politiques
La conversion stricte canonique est :
toIntXX()
toUintXX()
avec :
faults NumericConversionFault
lorsque la valeur peut être non finie, non entière ou hors plage.
A.9.1. Politiques mathématiques séparées
floor()
ceil()
round()
truncate()
restent des opérations sur le flottant. Elles se composent ensuite avec la conversion :
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 :
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 :
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 :
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 :
+0et-0donnent zéro ;NaNet les infinities produisentNotFinite;- une valeur fractionnaire produit
NotIntegralavant 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<T>(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.
int32 a = 42;
int8 small = ...;
int32 b = small; // ERROR
int32 c = small::toInt32(); // OK
A.12. NumericConversionFault
NumericConversionFault extends Fault
Codes sémantiques V1 :
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 :
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 :
- le listing mécanique exhaustif des membres concrets exposés par chaque primitive ;
- les noms définitifs des constantes/membres Core associés ;
- la représentation interne exacte des codes
NumericConversionFault; - les tests de conformité couvrant toutes les cellules de la matrice.