IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Mathématiques Discussion :

Extraire le chiffre situé au premier rang d'un nombre


Sujet :

Mathématiques

  1. #1
    Membre habitué

    Homme Profil pro
    Inscrit en
    Mars 2005
    Messages
    101
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2005
    Messages : 101
    Points : 141
    Points
    141
    Par défaut Extraire le chiffre situé au premier rang d'un nombre
    Bonjour,


    J'aimerais vérifier algorithmiquement qu'un nombre commence par "1", quel que soit son rang ("14", "13471", etc...) sans le convertir en chaîne de caractère (pour limiter la complexité en temps et espace).

    La seule formule que je trouve (en pseudo code, mais le langage serait sans doute Java) pour récupérer le chiffre situé au début d'un nombre:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    =FLOOR(LE_NOMBRE/(10^FLOOR(LOG10(LE_NOMBRE))))
    Mais je me demande s'il n'y a pas plus simple (et plus rapide pour le processeur)?

    Bien à vous,

  2. #2
    Membre émérite
    Homme Profil pro
    sans emploi
    Inscrit en
    Janvier 2014
    Messages
    539
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : sans emploi
    Secteur : Conseil

    Informations forums :
    Inscription : Janvier 2014
    Messages : 539
    Points : 2 601
    Points
    2 601
    Par défaut
    Bonjour,

    Il y a des problème si LE_NOMBRE vaut 0 ou est négatif. Si on part du principe que LE_NOMBRE≥0 alors il y a une version sans avoir à recourir aux flottants :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    while (LE_NOMBRE>9) LE_NOMBRE=LE_NOMBRE/10;
    if (LE_NOMBRE==1) commence_par_un=true;
    else commence_par_un=false;
    ou encore «sans calculs»
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    if (LE_NOMRE==1) || 
       (LE_NOMBRE≥10 && LE_NOMBRE≤19) ||
       (LE_NOMBRE≥100 && LE_NOMBRE≤199) ||
       (LE_NOMBRE≥1000 && LE_NOMBRE≤1999) ||
      ....
      commence_par_un=true;
    else
      commence_par_un=false;
    endif
    ou la version négative de la version précédente …

    Le plus simple est de tester plusieurs versions si tu as vraiment besoin de performances. Mais bon la source de tous les maux est dans une optimisation prématurée du code … Il faut toujours partir d'une version fonctionnelle, la profiler pour savoir où les optimisations auront le plus d'impact.

  3. #3
    Membre émérite

    Homme Profil pro
    Formation: Chimie et Physique (structure de la matière)
    Inscrit en
    Décembre 2010
    Messages
    1 333
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 77
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Formation: Chimie et Physique (structure de la matière)
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2010
    Messages : 1 333
    Points : 2 570
    Points
    2 570
    Billets dans le blog
    9
    Par défaut Extraire le chiffre situé au premier rang d'un nombre
    Bonjour,

    Je vois deux procédés symétriques limités aux nombres entiers, et basés sur l'itération conditionnelle d'une opération simple: (1) multiplication ou (2) division euclidienne par 10, l'étape essentielle consistant à déterminer le nombre de chiffres (c) de l'entier testé.
    C'est d'ailleurs ce que tu fais dans la séquence que tu proposes:
    Citation Envoyé par CetTer Voir le message
    ... J'aimerais vérifier algorithmiquement qu'un nombre commence par "1", quel que soit son rang ("14", "13471", etc...) ... La seule formule que je trouve pour récupérer le chiffre situé au début d'un nombre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    =FLOOR(LE_NOMBRE/(10^FLOOR(LOG10(LE_NOMBRE))))
    Mais je me demande s'il n'y a pas plus simple (et plus rapide pour le processeur) ...,
    la notion d'entier-plancher (FLOOR) renvoyant à la partie entière d'un nombre décimal.
    La seule réserve qu'on peut faire (mais d'autres ne seront peut-être pas du même avis) est l'imbrication forcenée des fonctions (4 niveaux !), dans le but probable de faire court à tout prix; pourquoi ne pas écrire (en reprenant la même notation):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    p=LOG10(LE_NOMBRE) ; i=FLOOR(p) ; j=10^(i) ;
    q=LE_NOMBRE / j ; k=FLOOR(q)
    séquence utilisant deux réels (p, q) et trois entiers, mais tout de même plus lisible ?

    1°) Première solution: chercher à encadrer l'entier étudié par les bornes appropriées ( a = 10^(c-1) ; b = 10^(c)-1 ), directement reliées au nombre de chiffres par le code suivant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     b:= 1; c:= 0;
    REPEAT 
        a:= b; b:= 10 * a; c:= c + 1 
    UNTIL b>LE_NOMBRE;
    Premier_Chiffre:= LE_NOMBRE DIV a ;
    C'est du Pascal (on ne se refait pas), mais cela se traduit sans peine.

    2°) La seconde solution (pour autant que je l'ai bien saisie) a été donnée par picodev:
    Citation Envoyé par picodev Voir le message
    ... Si on part du principe que LE_NOMBRE≥0 alors il y a une version sans avoir à recourir aux flottants :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    while (LE_NOMBRE>9) LE_NOMBRE=LE_NOMBRE/10;
    if (LE_NOMBRE==1) commence_par_un=true;
    else commence_par_un=false;
    Elle paraît l'emporter en concision.

    Cependant la variante proposée ensuite m'intrigue un peu:
    Citation Envoyé par picodev Voir le message
    ... ou encore «sans calculs»
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    if (LE_NOMRE==1) || 
       (LE_NOMBRE≥10 && LE_NOMBRE≤19) ||
       (LE_NOMBRE≥100 && LE_NOMBRE≤199) ||
       (LE_NOMBRE≥1000 && LE_NOMBRE≤1999) ||
      ....
      commence_par_un=true;
    else
      commence_par_un=false;
    endif
    Elle part d'une idée intéressante, mais s'exprime d'une manière lourdement répétitive et devient inapplicable au-delà des limites habituelles (232 ou 264 selon les langages). Comment faire pour LE_NOMBRE = 1000! (2567 chiffres, à vue d'oeil) ?
    Un algorithme apparenté au premier proposé (1), avec une boucle REPEAT ou WHILE, serait peut-être plus adaptée.

    # Le cas des entiers non-positifs n'est pas un problème: il suffit en préambule, de passer à la valeur absolue et d'exclure le zéro.


    Le français, notre affaire à tous
    Grand Dictionnaire Terminologique

  4. #4
    Membre émérite
    Homme Profil pro
    sans emploi
    Inscrit en
    Janvier 2014
    Messages
    539
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : sans emploi
    Secteur : Conseil

    Informations forums :
    Inscription : Janvier 2014
    Messages : 539
    Points : 2 601
    Points
    2 601
    Par défaut
    Citation Envoyé par picodev Voir le message
    [...]
    ou encore «sans calculs»
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    if (LE_NOMRE==1) || 
       (LE_NOMBRE≥10 && LE_NOMBRE≤19) ||
       (LE_NOMBRE≥100 && LE_NOMBRE≤199) ||
       (LE_NOMBRE≥1000 && LE_NOMBRE≤1999) ||
      ....
      commence_par_un=true;
    else
      commence_par_un=false;
    endif
    [...]
    Citation Envoyé par wiwaxia Voir le message
    [...]Cependant la variante proposée ensuite m'intrigue un peu:

    Elle part d'une idée intéressante, mais s'exprime d'une manière lourdement répétitive et devient inapplicable au-delà des limites habituelles (232 ou 264 selon les langages). Comment faire pour LE_NOMBRE = 1000! (2567 chiffres, à vue d'oeil) ?
    Un algorithme apparenté au premier proposé (1), avec une boucle REPEAT ou WHILE, serait peut-être plus adaptée.

    # Le cas des entiers non-positifs n'est pas un problème: il suffit en préambule, de passer à la valeur absolue et d'exclure le zéro.
    Évidemment je limite cette version aux entiers «natifs» et oui cela devient trop(?) lourd au-delà de 64bits. Mais si on utilise des entiers arbitrairement long il peut être plus efficace de commencer une conversion vers un string à partir de la gauche … à tester.
    Comme je le précise une optimisation prématurée d'un code est souvent une mauvaise chose.
    De plus je rajouterai que la concision d'écriture dans un langage donné n'est pas synonyme de performance. Un code plus long mais plus simple peu être plus performant. À nouveau il faut tester et garder à l'esprit que les meilleures optimisations seront celles qui seront pointées par un profiler …

  5. #5
    Membre habitué

    Homme Profil pro
    Inscrit en
    Mars 2005
    Messages
    101
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2005
    Messages : 101
    Points : 141
    Points
    141
    Par défaut
    Merci pour vos réponses, cela donne des pistes pour comparer des implémentations. Il s'agît bien de valeurs positives, résultant elles-même de la divisions d'entiers d'une longueur limitée (8 à 10 rangs).

  6. #6
    Membre émérite
    Homme Profil pro
    Inscrit en
    Mai 2008
    Messages
    2 040
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 2 040
    Points : 2 841
    Points
    2 841
    Par défaut Extraire le chiffre situé au premier rang d'un nombre
    Bonjour,

    Un léger mieux ?

  7. #7
    Membre émérite

    Homme Profil pro
    Formation: Chimie et Physique (structure de la matière)
    Inscrit en
    Décembre 2010
    Messages
    1 333
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 77
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Formation: Chimie et Physique (structure de la matière)
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2010
    Messages : 1 333
    Points : 2 570
    Points
    2 570
    Billets dans le blog
    9
    Par défaut
    Bonsoir,

    La divination n'est pas mon fort, mais je crois discerner dans l'énoncé sibyllin de la question posée
    Citation Envoyé par phryte Voir le message
    une version améliorée des fonctions ou algorithmes précédents ...

    Il me semble que 10^(log10(N)) = N , d'où: round(N/10^(log10(N))) = round(N/N) = round(1) = 1
    quel que soit l'entier positif de départ.
    Il y a comme un défaut dans la fonction proposée.


    Le français, notre affaire à tous
    Grand Dictionnaire Terminologique

  8. #8
    Expert éminent sénior Avatar de Flodelarab
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    5 243
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente (Poitou Charente)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 5 243
    Points : 13 458
    Points
    13 458
    Par défaut
    Bonjour

    Il suffit d'écrire le nombre en binaire et il commencera forcément par un 1.

    Cette réponse vous apporte quelque chose ? Cliquez sur en bas à droite du message.

  9. #9
    Membre émérite

    Homme Profil pro
    Formation: Chimie et Physique (structure de la matière)
    Inscrit en
    Décembre 2010
    Messages
    1 333
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 77
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Formation: Chimie et Physique (structure de la matière)
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2010
    Messages : 1 333
    Points : 2 570
    Points
    2 570
    Billets dans le blog
    9
    Par défaut Extraire le chiffre situé au premier rang d'un nombre
    Bonjour,

    Pour en revenir à la formule proposée:
    Citation Envoyé par phryte Voir le message
    la fonction d'arrondi < round(x) > est ici à proscrire en raison de la discontinuité présente au voisinage de tout argument semi-entier:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    round(k + u) = k si (u < 1/2) sinon round(k + u) = k + 1 
    { pour tout entier k >= 0 et tout réel du semi-ouvert [0 ; 1[}
    C'est la fonction partie entière < int(x) > qu'il faut utiliser - deux fois d'ailleurs si l'on veut parvenir à la réponse définitive:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    int(N/10^int(log10(N)))
    On vient ainsi au décalque (en je ne sais quel code, mais peu importe) de la formule initialement proposée:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    =FLOOR(LE_NOMBRE/(10^FLOOR(LOG10(LE_NOMBRE))))
    et déjà commentée plus haut.


    Le français, notre affaire à tous
    Grand Dictionnaire Terminologique

  10. #10
    Membre éclairé

    Homme Profil pro
    ingénieur de recherche
    Inscrit en
    Mars 2011
    Messages
    103
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : ingénieur de recherche
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Mars 2011
    Messages : 103
    Points : 864
    Points
    864
    Par défaut
    Bonjour

    Le processeur effectue en 1 tour machine la conversion d'entier en flottant, une fois cette opération effectuée, le nombre est sous forme mantisse, exposant:
    N = m * 2^e avec "m" entre 1 et 2 et "e" entier
    En cherchant un peut on trouve:
    N = m * 10^(e/ln2(10))
    N = m * 10^( e/ln2(10) - E( e/ln2(10) ) * 10^( E(e/ln2(10)) )

    Soit
    N = a*10^b
    Avec "a" dans [1, 20[ et "b" entier.

    Voilà donc la liste des opérations effectuées:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    N2 = (float)N;
    m=mantisse(N);
    e=exposant(N);
    e*= INV_LN2_10;
    e-=floor(e);
    m*=10^e;
    if m>=10 return 1;
    else return floor(e);
    Voilà donc un moyen d'éviter un logarithme et une division. Deux opérations en général lourde pour le processeur. Il reste tout de même le calcul de la puissance de 10 qui est lourde, mais étant donné que la puissance calculée est faible, le calcul peut être rapide.
    La récupération de la mantisse et de l'exposant ce font par décalage de bit. Le calcul des fonctions mathématiques tire souvent partie de l’écriture mantisse exposant:
    Mes tutoriels avancés sur la triangulation par filet à surface et sur les octree - N'hésitez pas à consulter les tutoriels et FAQ 2D/3D/jeux.

Discussions similaires

  1. [MySQL] extraire les chiffres d'une chaine
    Par megane dans le forum Langage SQL
    Réponses: 4
    Dernier message: 23/08/2006, 14h29
  2. [Tableaux] Extraire les chiffres dans une chaîne
    Par Digiduck dans le forum Langage
    Réponses: 8
    Dernier message: 16/08/2006, 14h33
  3. Extraire des chiffres
    Par nellynew dans le forum Access
    Réponses: 4
    Dernier message: 06/06/2006, 15h56
  4. Extraire un chiffre en binnaire
    Par BoBy9 dans le forum Algorithmes et structures de données
    Réponses: 10
    Dernier message: 27/03/2006, 18h39
  5. extraire 2 chiffres après virgule ?
    Par nerick dans le forum C
    Réponses: 2
    Dernier message: 13/12/2002, 17h10

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo