Répondre à la discussion
Affichage des résultats 1 à 5 sur 5

PHP ne sait plus soustraire !



  1. #1
    TheMoustic

    PHP ne sait plus soustraire !


    ------

    Bonjour,

    J'ai créé un page me permettant de trouver la valeur normalisée d'une résistance.

    Cependant, si l'on rentre 1,15 en choisissant la série E24, on devrait trouver 1,1 et 1,2 ohms comme valeur normalisée..

    Pour ce faire j'ai créé un tableau contenant les valeurs normalisées dans l'ordre croissant.

    Je fais ensuite dans une boucle la différence entre la valeur entrée ($res) et chaque valeurs normalisée. La plus petite différence est mise en mémoire dans la variable $min.

    Les valeurs normalisées étant rangées dans l'ordre croissant, quand la différence ($diff) ainsi calculée est plus grande que la valeur de $min précédemment enregistrée, je stop la boucle et retient la valeur normalisée trouvée (qui est donc la plus proche de $res).

    Et voilà où ça plante :

    Si la $diff = $min, alors $res se trouve pile poile entre 2 valeurs normalisées.. Et bien, même quand je tape 1.15, "barycentre" de 1.1 et 1.2 dans la série E24, le code ne me donne que 1,1 et c'est tout !!

    Regardez : http://forums.lms-stl.fr/_nofollow/_...tances/res.php

    Voici le code :

    Code PHP:
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" lang="fr" xml:lang="fr">
    <head>
    <title>Résistance norme E12 et E24</title>
    </head>
    <body>
    <?php
    //Déclaration
    if (isset($_POST['res'])) // Si la varaibale existe déjà, elle prend la valeur respective de la super globale post. 
    {
        
    $res $_POST['res'] ;
    }
    else 
    //Si elle n'existe pas, elle prend alors la valeur initiale de ""
    {
        
    $res "" ;
    }

    if (isset(
    $_POST['selserie']))
    {
        
    $selserie $_POST['selserie'] ;
    }
    else
    {
        
    $selserie // Numéro de l'option choisie au <select> - Sur 2 par défaut
    }

    $div // Indique le nombre de fois que l'on a dû diviser par 10 pour rendre la valeur de la résistance < 10
    $diff // Différence entre la résistance et une valeur normalisée
    $min 100 // Plus petite différence
    $i // Est incrémenté à chaque fois que la différenc calculée est plus petite que le minimum déjà enregistré
    $plage false // Est vrai si il existe 2 valeurs normalisées aussi proche l'une de l'autre de la résistance
    $coef // coefficient de dizaine multiplicateur (coef = 10^$div) - Sur 1 par défaut
    $prefixe "" // rien, k ou M (préfixe multiplicateur)
    $s 24 // Numéro de la série - Sur 24 par défaut (pour E24)
    //Fin déclaration

    ?>
    <form action="res.php" method="post">
        <p>Veuillez indiquer la valeur de la résistance (en Ω): <input type="text" name="res" value="<?php print $res ?>" /> (0 Ω < R < 10 MΩ)</p>
        <p>
            <select name="selserie">
            <option value="1" <?php if($selserie==1){ print 'selected'; } ?>>Série E12</option>
            <option value="2" <?php if($selserie==2){ print 'selected'; } ?>>Série E24</option>
            </select>
        </p>
        <p><input type="submit" value="Valider" /></p>
    </form>
    <?php

    If (!empty($res)) // Vérifie si une résistance a été tapée
    {
        if (
    $res OR $res bcpow(10,6)) // Vérifie que la résistance est correcte
        
    {
            print 
    '<br /><p>Veuillez renseigner une valeur comprise entre 0 Ω et 10 MΩ !</p>';
        }
        else 
    //Exécute le script
        
    {
            
    $res str_replace(",""."$res) ; // Empêche que res contienne une virgule (remplace "," par ".")
            
            
    if ($selserie == 1)
            {
                
    //Série E12
                
    $serie = array(1.01.21.51.82.22.73.33.94.75.66.88.2);
                
    $s 12 ;
            }
            else if (
    $selserie == 2)
            {
                
    //Série E24
                
    $serie = array (1.01.11.21.31.51.61.82.02.22.42.73.03.33.63.94.34.75.15.66.26.87.58.29.1);
                
    $s 24 ;
            }
            
    $t=0//temp - témoin
            
            //Cherche la valeur de $res la plus proche dans la série sélectionnée
            
    foreach ($serie as $element)
            {
                while (
    $res >= 10// ramène la valeur de $res < 100
                
    {
                    
    $res $res 10 ;
                    
    $div++ ;
                }
                
                
    $diff $res $element ;
                
                if (
    $diff // Donne la valeur absolue de $diff
                
    {
                    
    $diff $diff * (-1) ;
                }
                
    $t++ ; //temp
                
    // Début - temporaire, vérification de la bonne exécution du script
    print '<br><br>res = '.$res.'<br/>' ;
    print 
    'E'.$s.': '.$serie[$t-1].'<br/>' ;
    print 
    'diff<sub>('.$t.')</sub> = '.$diff.'<br/>' ;
    print 
    'min<sub>(avant)</sub> = '.$min.'<br/>' ;
    print 
    'min<sub>(avant)</sub> - diff<sub>('.$t.')</sub> = ' ;
    print 
    $min-$diff.'<br/>' ;
    // Fin - temporaire, vérification de la bonne exécution du script
                
                
    if ($diff $min//Stock la valeur la plus petite de $diff
                
    {
                    
    $min $diff ;
                    
    $i++ ;
                    
    print 
    'diff<sub>('.$t.')</sub> < min<sub>(avant)</sub><br/>' //temp
                    
                
    }
                else if (
    $diff == $min// En cas d'égalité avec une autre valeur noramlisée (permet de retenir les 2 valeurs)
                
    {
                    
    $plage true ;
                    
    print 
    'diff<sub>('.$t.')</sub> = min<br/>' //temp
                    
                
    }
                else if (
    $diff $min// Les valeurs normalisées étant rangées dans l'ordre croissant, la boucle est arrêtée dès que $diff > $min
                
    {
    print 
    'diff<sub>('.$t.')</sub> > min<sub>(avant)</sub><br/>' //temp
    print '<br/>break !!<br/>' //temp
                    
    break ;
                }

    print 
    'min<sub>(après)</sub>: '.$min.'<br/>' //temp
                
            
    }
            
            
    $coef bcpow(10,$div) ;
            
            if (
    $div >= AND $div 5)
            {
                
    $prefixe "k" ;
                
    $coef bcpow(10,$div-3) ;
            }
            else if (
    $div >= 5)
            {
                
    $prefixe "M" ;
                
    $coef ;
            }
            
            if (
    $plage)
            {
                print 
    '<p><br/>La résistance de la série E'.$s.' la plus proche est: <b>'.$serie[$i-1]*$coef.'</b> '.$prefixe.'Ω ou: <b>'.$serie[$i]*$coef.'</b> '.$prefixe.'Ω</p>' ;
            }
            else
            {
                print 
    '<p><br/>La résistance de la série E'.$s.' la plus proche est: <b>'.$serie[$i-1]*$coef.'</b> '.$prefixe.'Ω</p>' ;
            }
        }
    }
    ?>
    </body>
    </html>
    PS: Dsl, mais visiblement tout est aligné à gauche, je joint donc le fichier au format texte pour ceux qui veulent.

    Merci de votre aide

    -----
    Fichiers attachés Fichiers attachés
    Rien ne sert de courir, non, ça ne sert à rien.

  2. Publicité
  3. #2
    Towl

    Re : PHP ne sait plus soustraire !

    Tu viens de découvrir les joies des nombres flottants Un nombre a virgule n'est jamais ce que l'on pense

    On va faire un test rigolo, fait en python car j'ai pas d'interpreteur php sur ma machine, mais tu devrais reconnaitre ton code :

    Code:
    r = [ 1.0,1.1,1.2,1.3,1.5,1.6,1.8,2.0,2.2,2.4,2.7,3.0,3.3,3.6,3.9,4.3,4.7,5.1,5.6,6.2,6.8,7.5,8.2,9.1]
    res = 1.15
    
    min = 100
    plage = False
    for element in r:
        diff = res - element
        if diff < 0:
            diff *= -1
        print element, diff, min, (diff - min)
        if diff < min:
            min = diff
        elif diff == min:
            plage = True
        elif diff > min:
            break
    print plage
    qui me donne
    Code:
    element   diff     min     (diff - min)
    1.0       0.15     100     -99.85
    1.1       0.05     0.15     -0.1
    1.2       0.05     0.05     2.22044604925e-16
    False
    Comme tu peux le voir, je n'ai pas toujours ce à quoi on peut s'attendre

    Si tu veux éviter cela, soit tu essaye de travailler sur des entiers, soit tu fais non pas un test d'égalité, mais un test de "presque égalité, à un Epsilon pret"
    Ce qui te donnerai un
    Code:
      if diff < min:
            min = diff
        elif (diff - min) < 0.0001:
            plage = True
    Et la ton code va marcher
    The only limiting factor of the Linux operating system, is his user. - Linus Torvalds

  4. #3
    padboy

    Re : PHP ne sait plus soustraire !

    Probablement un erreur de type.

    Tu devra faire un casting sur ta variable.

  5. #4
    Towl

    Re : PHP ne sait plus soustraire !

    Ce n'est pas une erreur de type mais une erreur d'interprétation des flottant. Un nombre à virgule n'est pas stocké sous forme exacte, meme quand il est simple, mais sous sa représentation normalisée la plus proche.
    Et il se trouve que 1.2 n'est pas tout à fait 1.2, mais plutot 1.2000000000000XXX et 1.15 doit plutot être 1.150000000000XXXX (flemme de me tapper la norme pour donner les valeurs exactes ) et la soustraction des deux ne donne donc pas 0, mais quelque chose de très proche (ici 0.000000000000000222044604925. ..)

    Or l'égalité, c'est l'égalité, tu ne peux pas avoir de différence, meme avec un facteur 10^-16 comme ici. D'ou l'insertion d'un epsilon qui permet de masque cette inégalité matérielle et non logique
    The only limiting factor of the Linux operating system, is his user. - Linus Torvalds

  6. #5
    TheMoustic

    Re : PHP ne sait plus soustraire !

    Super !!

    Merci beaucoup !!!
    Rien ne sert de courir, non, ça ne sert à rien.

  7. A voir en vidéo sur Futura

Discussions similaires

  1. Programme pour soustraire 2 courbes.
    Par Fajan dans le forum Chimie
    Réponses: 9
    Dernier message: 27/10/2009, 10h10
  2. Programme pour soustraire 2 courbes.
    Par Fajan dans le forum Physique
    Réponses: 11
    Dernier message: 27/10/2009, 05h12
  3. soustraire une tension de référence
    Par alainav1 dans le forum Électronique
    Réponses: 8
    Dernier message: 26/10/2007, 17h59
  4. Qui sait ? Moi je sais pas ! Sait-on jamais ?
    Par Rann dans le forum Discussions scientifiques
    Réponses: 1
    Dernier message: 08/05/2007, 13h33
  5. Insérer une page php avec variables (ex : page.php?nom=jean) grâce au javascript
    Par Bossisman dans le forum Logiciel - Software - Open Source
    Réponses: 4
    Dernier message: 21/05/2005, 17h37
Découvrez nos comparatifs produits sur l'informatique et les technologies.