Division d'un réel par un autre

Résolu
Skanenruf Messages postés 38 Date d'inscription dimanche 12 octobre 2008 Statut Membre Dernière intervention 30 juin 2010 - 27 oct. 2009 à 12:57
Skanenruf Messages postés 38 Date d'inscription dimanche 12 octobre 2008 Statut Membre Dernière intervention 30 juin 2010 - 19 nov. 2009 à 19:25
Bonjour,

Je suis en train de programmer une classe contenant les opérations élémentaires sur les réels. J'ai trouvé cela sur les entiers (BigInt)... mais jamais sur les réels.

L'avantage de ces techniques c'est qu'en stockant les chiffres dans une chaine et la virgule dans une variable numérique (faisant office de mantisse/significande) on peut créer une classe de calcul théoriquement infini, dont la seule limite repose sur le temps de calcul.

Je possède une structure que j'ai appelé Reel, dans celle ci il y a une variable string Valeur contenant la suite de chiffres qu'est un nombre (sans séparateur décimal), une variable integer Significande (l'équivalent la mantisse dans le langage courant) qui contient la position de la virgule (adaptée sur la notation scientifique, à savoir que lorsque Significande = 0, la virgule est le second caractère de la chaine) et une variable String Signe contenant "+" ou "-". Cette structure représente donc théoriquement est réel de longueur (quasi) infinie.

J'ai déjà programmé les fonctions d'addition et de soustraction sur ce type Reel en m'appuyant sur les programmes de CE2 (quand on posait nos opérations ^^). Mais je bloque sur la conception de la fonction de division car les programmes scolaire n'expliquent comment diviser un réel par un autre réel (le diviseur est toujours entier).

Je cherche donc à trouver l'algorithme permettant de diviser un réel par un autre (et si c'est possible également celui de la division euclidienne). Est-ce que quelqu'un pourrait m'indiquer cela ?

Merci beaucoup de votre attention !
Léo Nicoletti.
A voir également:

31 réponses

BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
29 oct. 2009 à 17:48
Aucune idée depuis VB, je n'ai pas regardé.
Si vraiment probleme, suffirait de faire une DLL (en C) qui servirait de wrapper entre VB et GMP.

ciao...
BruNews, MVP VC++
0
Skanenruf Messages postés 38 Date d'inscription dimanche 12 octobre 2008 Statut Membre Dernière intervention 30 juin 2010
29 oct. 2009 à 19:40
Bonsoir à vous deux,

Merci BruNews pour la librairie GMP. Il faut reconnaître qu'arriver à utiliser cette librairie depuis .NET serait le must (puisqu'elle contient également un évaluateur d'expression - algorithme récursif).

Us_30, je ne savais pas que l'on pouvait ouvrir les macros depuis Excel (ça doit être la seconde fois que j'ouvre un tableur ^^) j'ai tellement pour habitude d'utiliser directement l'IDE Visual Studio.

J'ai retrouvé l'extrait de ton code sur l'addition dans le module GN. Mais il reste des choses que je ne saisis pas bien, si je dois résumer mes questions sur ton algorithme :

'Addition
    For t = lgmul - Multiple + 1 To 1 Step -Multiple
        V1 = Mid$(Nb1, t, Multiple) ' A quoi sert le "$" derrière la fonction Mid ? Est-il particulier à VB6 ?
        V2 = Mid$(Nb2, t, Multiple)
        R = V1 + V2 + Ret
        lr = Fix(Log(R + 0.11) / ln10) + 1
        If lr Multiple + 1 Then Ret 1 Else Ret = 0
        Mid$(Total, t - lr + Multiple, lr) = CStr(R)
    Next t


Je ne comprends pas non plus les trois dernières lignes à l'intérieur de la boucle. A quoi servent ces logarithmes ? Ma technique pour récupérer la retenue si besoin n'est elle pas plus efficace ? De plus, je ne comprends pas du tout la dernière ligne : comment peux-tu utiliser une attribution sur une fonction !?

J'ai un peu regardé les autres fonctions que tu as implémenté dans ta macro et je remarque que tu ne sous-appelle (que très peu) les fonctions opératrices. Je veux dire que tu n'utilises pas les fonction PGN() n-1 fois pour le calcul d'une factorielle. Je suppose que c'est très intéressant car appeler plusieurs fois une même fonction est lourd. De même il est possible de programmer une fonction de multiplication entre a et b en appelant b-1 fois l'addition de a avec a, mais je suppose que ces techniques sont à éviter à tout prix ?

Tu dis que de n'utiliser que les fonctions du framework est intéressant niveau optimisation mais, comment savoir lesquelles en font partie ou non et je suppose qu'il faut signaler au compilateur de n'utiliser que le framework ? Pour ce qui est de la taille du boolean, j'avais été assez étonné d'apprendre que le boolean de Visual Basic (je ne sais plus si c'était .NET ou pas) était stocké sur plus d'un bit (mathématiquement nécessaire pour stocker une valeur booléenne). Je viens de chercher un peu et j'en suis venu à la conclusion que nos processeurs travaillant sur bien plus d'un octet (32bits voir 64bits) mettent plus de temps à atteindre les octets ou bit à l'intérieur d'un bloc de 32 bits (quadlet) ou de 64 bits (octlet)... Source

Amicalement, Léo.
0
Skanenruf Messages postés 38 Date d'inscription dimanche 12 octobre 2008 Statut Membre Dernière intervention 30 juin 2010
30 oct. 2009 à 12:05
Bonjour Us_30,

Déjà, je tiens à te remercier pour toutes tes réponses et ton tutoriel sur l'optimisation qui m'aident beaucoup à comprendre l'optimisation. Je m'aperçois que mes algorithmes ne sont pas du tout optimisés.

Je te remercie pour tes explications ligne par ligne, je comprends bien mieux le principe (en gros toujours préférer les formules mathématiques aux manipulations de chaines). Juste une petite remarque sur la dernière ligne (Mid$(Total, t - lr + Multiple, lr) = CStr(R)), en algorithmique j'ai vu que le symbole "<-" était utilisé pour l'attribution (par exemple sur ma calculatrice TI84+), il ne l'ai que très peu dans les langages car long à aller chercher au clavier. Mais cette expression est mathématiquement fausse : a=a+1. C'est pour cela que cette dernière ligne me posait problème mais c'est bon j'ai compris !

Bon comme je travaille en VB.NET, l'histoire du type variant ne me concerne pas, mais cela reste tout de même étrange que Microsoft ai crée ce type (c'est comme la possibilité de ne pas déclarer ses variables, ça ne va pas avec la rigueur exigée d'un langage de programmation). En parlant de framework, j'ai effectivement pu tester l'efficacité de désactiver la référence du VisualBasic (un algorithme qui n'utilisait pas de fonction de VB est passé en 172 millisecondes à 141 uniquement en désactivant la référence). Mais mon problème c'est que mon logiciel est gros et que le module de calcul (à optimiser) n'est qu'une classe parmi d'autres, donc pour pouvoir désactiver cette référence uniquement sur cette classe je me suis dis que compiler une DLL serait intéressant.
Qu'en penses-tu ? L'appel d'une DLL n'est-il pas long ?

Merci beaucoup une fois de plus !
Léo.
0
Skanenruf Messages postés 38 Date d'inscription dimanche 12 octobre 2008 Statut Membre Dernière intervention 30 juin 2010
30 oct. 2009 à 19:45
Bonsoir,

Je ne peux que te remercier de toutes ces informations et indications que tu m'as généreusement indiqué. J'ai de quoi bien améliorer mon module de calcul et j'ai surtout gagné de sérieuses connaissances sur l'optimisation d'algorithmes (domaine qui m'était jusqu'alors totalement inconnu - il m'est arrivé de redimensionner (avec ReDim Preserve) dans une boucle maintenant je sais que c'est très mauvais !). Pour la référence à Visual Basic, je pense que le mieux est de commencer par la désactiver (c'est comme les options explicit et autre), cela donne un certain cadre à l'écriture de programmes !

Wikipédia m'informe que l'écriture scientifique d'un nombre est constitué de : un signe, une mantisse (je m'étais trompé sur son sens en début de sujet), une base et un exposant. L'exposant représente le flottant (position de la virgule) et la base représente la base mathématique du nombre (en quelque sorte la cardinalité de l'alphabet utilisé pour représenter un nombre). Or, dans mon programme je veux laisser la possibilité à l'utilisateur de choisir la base d'un nombre.
A ton avis, est-il préférable d'intégrer la base dans les fonctions de calcul (addition, soustraction, multiplication...) ou alors de créer une fonction supplémentaire de "conversion de base" ?

Encore une petite chose qui m'intrigue (je suis de nature curieuse ce qui ne doit pas faire votre affaire ^^)... Dans tous le sujets que je trouve traitant de ces classes de calcul sur des nombres "théoriquement" infinis, le terme "bistromathique" apparait plus ou moins, saurait-tu ce qu'il signifie ? (ni le Petit Robert ni Google, ni Wikipédia ne connaissent)

Après tant de réponses que tu m'as apporté, je te dois bien ça : je remarque que tu n'as pas d'algorithme pour effectuer des divisions sur les grands nombres, or dans cette page, quelqu'un propose une rapide explication d'une méthode pour effectuer une division euclidienne (ça peut peut-être t'intéresser). De plus, je remarque que tu possèdes une fonction "InverseGN" qui renvoie l'opposé mathématique d'un nombre (l'opposé est le nombre de signe contraire), il me semble que l'inverse de x est plutôt 1/x que -x...

Je te souhaite une bonne soirée !
Léo Nicoletti.
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
us_30 Messages postés 2065 Date d'inscription lundi 11 avril 2005 Statut Membre Dernière intervention 14 mars 2016 10
13 nov. 2009 à 19:00
Oupsss... J'ai loupé la suite... donc un peu plus tard, désolé...

Pour répondre à :

"A ton avis, est-il préférable d'intégrer la base dans les fonctions de calcul (addition, soustraction, multiplication...) ou alors de créer une fonction supplémentaire de "conversion de base" ? "

Bonne question ! Je ne sais pas vraiment te répondre... Néanmoins, je dirais que le plus simple sera le meilleur, donc plutôt faire une "conversion de base" qui aura la bonne idée d'être utilisable pour n'importe quelle base, sans refaire toutes les autres fonctions...

le terme "bistromathique" [...], saurait-tu ce qu'il signifie ?
Euh... ben, non.

pour effectuer des divisions sur les grands nombres
... Mieux vaut utiliser, soit le principe inverse de la multiplication des grands nombres (mais dans ce cas on ne peut pas dépasser un groupe de 8 chiffres), soit utiliser l'algorithme de Newton (vitesse quadratique)...

tu possèdes une fonction "InverseGN" qui renvoie l'opposé mathématique
Bien vu ! Elle sera appeler OppGN... à la future prochaine mise à jour...

Amicalement,
Us.
0
Skanenruf Messages postés 38 Date d'inscription dimanche 12 octobre 2008 Statut Membre Dernière intervention 30 juin 2010
13 nov. 2009 à 20:44
Salut,

Merci pour ta réponse, ce n'est absolument pas grave pour le temps de réponse. J'ai eu de nombreuses réponses qui m'ont beaucoup fait avancer dans la compréhension de ce genre de classes de calcul.

Mieux vaut utiliser, soit le principe inverse de la multiplication des grands nombres (mais dans ce cas on ne peut pas dépasser un groupe de 8 chiffres), soit utiliser l'algorithme de Newton (vitesse quadratique)...

J'avoue que j'ai du mal à comprendre, multiplier par l'inverse pour diviser je veux bien pour calculer l'inverse il faudra bien effectuer une division (1/x) ! Si j'ai bien compris, le groupe de 8 chiffre représente les divisions que l'on peut opérer grâce aux types numériques de VB... dans ce cas ce n'est pas très intéressant pour des grands nombre !

Tu parles d'un certain algorithme de Newton, quand je fais des recherches je tombe sur un algorithme permettant de résoudre des équations du type f(x)=0 (trouver les racines d'une fonction) mais rien permettant d'effectuer des divisions ! On revient en fait au sujet initial...

Il m'est impossible de commencer l'implémentation des fonctions (en développement limité/illimité) sans la division.

Merci une fois de plus !
0
Skanenruf Messages postés 38 Date d'inscription dimanche 12 octobre 2008 Statut Membre Dernière intervention 30 juin 2010
14 nov. 2009 à 14:52
Bonjour Us_30,

Merci pour ton fichier PowerPoint qui m'a beaucoup aidé à comprendre l'algorithme de Newton. J'ai effectué cette implémentation itérative sur la console de VB.NET :

    Sub Main()
        Dim a As Decimal =  Val(Console.In.ReadLine())
        Dim x As Decimal = 1
        For i As UInteger = 1 To 10 ' nombre d'itérations
            x = x * (2 - a * x)
        Next i
        Console.Out.WriteLine("1/" & a & "=" & x)
        Console.In.ReadLine()
    End Sub


Remarque : Je définis de façon constante (dans le code) X0 =1, cela évite toute la première étape d'estimation d'ordre de grandeur de X0. Cela n'est pas très optimiser mais lors de mon implémentation dans ma classe de calcul je ferais très attention à choisir un X0 le plus adapté possible.

L'algorithme marche parfaitement pour des réels comme 0.123456 ou 0.52369817 dans le fichier PowerPoint) mais outre le fait que je ne puisse dépasser la quatrième itération il renvoie des résultats invraisemblables avec des réels comme 14.

Est-ce que tu penses que si j'applique cette algorithme à des types de réels infinis (avec mantisse, exposant et signe) il sera fonctionnel ?

[b]Merci une fois de plus !
(je suis presque au bout de mes peines)/b
0
Skanenruf Messages postés 38 Date d'inscription dimanche 12 octobre 2008 Statut Membre Dernière intervention 30 juin 2010
14 nov. 2009 à 18:47
Salut,

Je pense avoir compris la majeure partie de ton message mais excuse moi je revenir sur certains points... le développement avec précision est totalement nouveau pour moi (addition, soustraction et multiplication ne posent pas de problèmes de précision).

Si je dois résumer :
[list]
[*] Je définis x le plus proche possible de 1/a avec a réel multiprécision. Pour cela j'utilise la division sur les types numériques de VB en prenant les 8 premiers chiffres (précision simple) de la mantisse ainsi qu'en effectuant l'inverse de la puissance de 10 (revenant à effectuer l'opposé de l'exposant : 1/10^12=10^-12).
[*] J'effectue l'algorithme de Newton en boucle en suivant la convergence quadratique pour m'arrêter à la précision désirée.
/list

C'est surtout le second point qui m'est flou (la convergence quadratique) : si X0 possède 2 chiffres,
X1 en possèdera 2^2 chiffres justes
X2 en possèdera 2^3 chiffres justes (=2^2*2)
X3 en possèdera 2^4 chiffres justes (=2^3*2)
ou alors on effectue le carré du nombre de chiffres juste du X précédent (et non tout le temps de X0)
X1 possèdera 2^2 chiffres justes
X2 possèdera 2^4 chiffres justes (=(2^2)^2)
X3 possèdera 2^8 chiffres justes (=(2^4)^2)
En gros, est-ce la carré du nombre de chiffres justes de la valeur précédente de X (2° possibilité) ou le nombre de chiffres justes vaut (nombre de chiffres justes de X0)^(itération+1) ?

Merci énième fois !!!
0
Skanenruf Messages postés 38 Date d'inscription dimanche 12 octobre 2008 Statut Membre Dernière intervention 30 juin 2010
15 nov. 2009 à 15:12
Bonjour,

Ce qui m'a déstabilisé dans le PTT c'est la partie entière... Tu as bien fait de me donner la formule permettant d'obtenir le nombre tour en fonction de la précision (je n'ai encore rien fait en cours quoi que ce soit qui s'apparente de près ou de loin à un logarithme).

J'ai réalisé ce programme sur la console de VB.NET (le logarithme népérien est la fonction log et le logarithme décimal log10 dans l'espace de nom System.Math) :

    Sub Main()
        Dim a As Decimal = 0.52369817
        Dim x As Decimal = 1.5
        Dim z As UInteger = 16
        Dim fin As UInteger = Ceiling(Log(z / x) / Log(2)) + 1
        For i As UInteger = 1 To fin
            x *= (2 - a * x)
        Next i
        Console.Out.WriteLine(Mid(x.ToString, 1, z + 2))
        Console.In.ReadLine()
    End Sub


Ce code m'indique que si je prolonge l'exemple du PTT, la ligne suivante serait : x5=x4(2-a.x4)=1.9094968386083915 avec Z=16 (chiffres justes).

Le problème étant que si je souhaite une précision n'étant pas dans le suite quadratique (2 4 8 16 32...) les résultats peuvent être erronés ainsi il faudrait que je fasse une condition qui augmente Z à la valeur quadratique supérieur pour le calcul puis je découpe la chaine avec la première valeur de Z (avec mon Mid() ou une fonction plus optimisée) mais je vois pas trop comment faire...

Sinon, j'arrive à faire marcher l'algorithme pour des nombres comme 14 et tapant 1/14 sur ma calculatrice et en donnant à x une valeur approchée, cette technique (qui simule le précalcul de x qui sera effectué par les types de VB avant la structure itérative) marche (encore) pour obtenir l'inverse d'un nombre comme 123456789 (avec x=0.000000008) mais j'ai peur que pour des très grands nombres l'écart entre le x0 obtenu (par division VB) et a soit trop important pour que l'algorithme puisse démarrer sa division.

Merci beaucoup !!

PS. Je ne sais comment te remercier pour toutes les réponses que tu m'apportes !
0
Skanenruf Messages postés 38 Date d'inscription dimanche 12 octobre 2008 Statut Membre Dernière intervention 30 juin 2010
18 nov. 2009 à 14:48
Salut Us_30,

Merci une ultime fois pour toutes tes réponses, je pense que tu as clarifié tous les points principaux sur cette multiprécision. Je n'ai plus qu'une chose à faire : ouvrir VB.NET, créer une nouvelle classe, une structure de réel (mantisse, exposant, signe) et me lancer d'arrache pied dans le développement de ces quelques fonctions élémentaires (addition arithmétique, soustraction arithmétique, multiplication, puissance, division, modulo...). Le tout c'est de s'accrocher et de ne pas se laisser démoraliser !

J'aurais juste deux dernières (toutes) petites questions :

- Pour programmer la fonction puissance (a^b), je me demandai si il était préférable d'utiliser une simple itération de la fonction multiplication (programmée précédemment) ou alors un algorithme particulier (comme l'exponentiation) ?

- Il s'en suivra ensuite une période où je devrais programmer un maximum de fonctions mathématiques avec cette structure de réel. Je cherche les implémentations (quelque soit le langage, c'est l'algorithmique qui m'intéresse) d'un maximum de fonctions (fonctions de trigonométrie : sin, cos, tan, sinh, cosh, tanh, asin, acos, atan... ainsi que de nombreuses autres fonctions comme les logarithme, l'exponentielle etc... etc...) pour les développements limités et illimités, est-ce que par hasard tu saurais où trouver ces implémentations ?
(Note : Je peux comprendre avec un peu d'entrainement des fonctions sous la forme de grands opérateurs)

Merci une fois de plus ! Je vais me lancer dans cette classe la semaine prochaine, si cela ne te dérange (toujours) pas je te poserai sur ce sujet les problèmes que je pourrai rencontrer. Mais a priori c'est tellement bien expliqué que je ne devrais pas rencontrer trop de problème !!

Merci ! Léo Nicoletti.
0
Skanenruf Messages postés 38 Date d'inscription dimanche 12 octobre 2008 Statut Membre Dernière intervention 30 juin 2010
19 nov. 2009 à 19:25
Le principe de l'exponentiation rapide est très simple et méchamment efficace ! Je te remercie pour toutes tes indications. Je considère donc ce sujet comme résolu (je suppose qu'il n'y a pas de bouton !).

Merci.
Léo.
0
Rejoignez-nous