Gérer la précision des nombres flottants en AutoLISP avec FIX

J’essaie de créer une fonction AutoLISP pour convertir des longueurs métriques en format Point Kilométrique (ex: 45.3 => 45+300). J’ai remarqué que l’instruction (fix (* (- 45.3 45) 1000)) retourne 299 au lieu du 300 attendu. Comment puis-je obtenir le résultat correct de 300 ?

L’erreur de retour de la fonction (fix) est due aux erreurs de précision en virgule flottante inhérentes à la manière dont les ordinateurs représentent les nombres décimaux en binaire. Un nombre comme 0.3 ne peut pas être représenté exactement, ce qui entraîne de légers écarts lors des calculs. Voici deux méthodes pour contourner ce problème et obtenir le résultat attendu :

  1. Distribuer la multiplication pour éviter les intermédiaires imprécis :

    • Principe : Au lieu de calculer la différence (0.3) puis de multiplier, multipliez chaque terme par le facteur avant de soustraire. Cela permet de travailler avec des nombres entiers (ou des flottants sans partie décimale significative) avant la soustraction, minimisant ainsi les erreurs de précision.
    • Procédure :
      1. Modifiez votre expression comme suit :
        (fix (- (* 45.3 1000.0) (* 45.0 1000.0)))
        
      2. Le calcul (* 45.3 1000.0) donnera 45300.0 et (* 45.0 1000.0) donnera 45000.0. La soustraction (- 45300.0 45000.0) produira 300.0, que (fix) convertira correctement en l’entier 300.
  2. Convertir temporairement en chaîne de caractères pour forcer l’arrondi :

    • Principe : Cette méthode utilise la conversion en chaîne de caractères pour forcer un arrondi à l’entier le plus proche avant de le reconvertir en nombre entier.
    • Procédure :
      1. Utilisez la fonction (rtos) (Real TO String) pour convertir le résultat du calcul en une chaîne de caractères avec zéro décimale, puis (atoi) (Ascii TO Integer) pour le reconvertir en entier.
      2. Modifiez votre expression comme suit :
        (atoi (rtos (* (- 45.3 45) 1000) 2 0))
        
      3. Explication : Le calcul (* (- 45.3 45) 1000) pourrait donner un résultat comme 299.99999999999994. La fonction (rtos ... 2 0) convertit ce nombre en une chaîne de caractères avec 0 décimale, ce qui force un arrondi à l’entier le plus proche (ici, "300"). (atoi "300") retourne ensuite l’entier 300.

Prévention : Pour des calculs nécessitant une précision absolue avec des nombres décimaux, il est souvent plus sûr de travailler avec des entiers en multipliant toutes les valeurs par un facteur approprié (par exemple, 1000 pour les millimètres) dès le début de vos calculs, et de ne diviser qu’à la fin si un résultat décimal est requis. Cela permet d’éviter de manipuler directement des nombres flottants intermédiaires susceptibles d’introduire des erreurs de précision.