[.NET 2] Math.Pow est buggé !

Introduction

Imaginons que vous souhaitiez obtenir la racine cubique de -0.5.

Vous écrivez dès lors le code suivant : -0.5 ^ (1/3) ou Math.Pow(-0.5, 1/3)

Quelle n'est pas votre suprise d'apprendre que cela fait... NaN ! Pas très pratique quand on sait que cette racine existe pourtant bel et bien !

Pourquoi ce bug ?

En fait, quand vous avez un exposant inférieur à 1, Math.Pow utilise une formule contenant le logarithme. Or le logarithme n'est défini que pour les nombres positifs. Conclusion, pour les nombres négatifs, point de racine cubique.

Comment corriger ce bug ?

Il faut dès lors ruser... Voici ma solution (VB), qui consiste en fonction "v(n, x)"

Public Module MathModule
    Public Function v(ByVal c As Double, ByVal x As Double) As Double
        If x < 0 Then 'Si le nombre est négatif
            v = -((-x) ^ (1 / c)) 'Chercher la racine du nombre positif
            If Math.Round(v ^ c, 3) <> Math.Round(x, 3) Then 
                v = Double.NaN 'Et renvoyer NaN si cette racine ne s'applique pas
            End If
        Else
            v = x ^ (1 / c)
        End If
    End Function
    Public Function v(ByVal x As Double) As Double
        v = x ^ (0.5)
    End Function
End Module
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :
Publié 10 novembre 07 09:10 par FREMYCOMPANY
Classé sous : , ,

Commentaires

# brunews said on novembre 10, 2007 21:57:

Que ce ne soit pas pratique OK mais dire que c'est buggé quand la règle du jeu est respectée...

Math.Pow(x, y)

Si x &lt; 0 mais pas Moins l'infini:

Valeur de retour = Nan

DIXIT MSDN.

# Matou said on novembre 10, 2007 23:17:

Selon moi, il s'agit plutôt d'un bug documenté (un peu comme la gestion de certaines dates en OpenXML).

# smo said on novembre 11, 2007 08:43:

Ce n'est pas "buggé", c'est clairement codé comme cela. Cf ici:

http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=94376

et je crois que c'est compatible avec l'API équivalente Java (mais je ne suis pas sûr ;-)

# FREMYCOMPANY said on novembre 11, 2007 13:08:

Oui, je suis d'accord avec toi Matou, pour moi ce n'est rien de plus qu'un "bug" documenté.

Si une fonctione matématique ne renvoie pas la réponse qu'elle est censée fournir, c'est qu'elle est buggée. Que ce soit expliqué dans la MSDN ou pas...

Si la fonction 5-(-5) renvoyait 0, mais que la documentation prévient que la soustraction de nombres de signe opposée renvoie leur addition, vous n'allez pas dire "que ce n'est pas un bug"...

Surtout que

Dim E as Double = -1.1

E ^ (1/3) = -1.1 ^ (1/3) renvoie False... car -1.1 ^ (1/3) est précompilé et renvoie bien la bonne réponse (-1.331).

# RaptorXP said on novembre 11, 2007 13:36:

Rien à voir avec un bug, ni même un bug by design. NaN est la bonne réponse (mathématiquement parlant).

Quand tu calcules 1/3, le résultat en mémoire n'est pas égal à 1/3, c'est normal puisqu'il y a une infinité de 3.

Du coup le résultat de pow n'est pas réel, donc NaN est bien la bonne réponse.

Si tu calcules (-1)^2.00001 tu auras le même problème.

Pour éviter ça tu n'as qu'a toujours calculer la puissance d'un nombre positif (et ajuster le signe à la main).

Morale de l'histoire : renseigne toi avant de crier au loup.

# FREMYCOMPANY said on novembre 11, 2007 20:52:

Ce que tu dis est faux car si je tape -1.1^(1/3) directement dans le code, j'obtiens bien le résultat attendu ! Et si je fais Pow(1.1, 0.3333333333333331), aussi.

Donc ton argument ne tiens pas

# RaptorXP said on novembre 12, 2007 15:44:

Ce n'est pas un "argument", c'est ce qu'on apprend en math.

Si tu ne me crois pas regarde sur Wikipedia :

http://fr.wikipedia.org/wiki/Puissance_(math%C3%A9matiques_%C3%A9l%C3%A9mentaires)

"(Les puissances entières sont en fait des cas particuliers de) la fonction exponentielle :

a^b = exp(b*ln a) définie par tout réel a STRICTEMENT POSITIF"

Si tu veux étendre la définition à a négatif, tu fais appel aux racines n-ièmes de l'unité qui ne sont définies que pour n entier. Donc les seules puissance auxquelles tu *pourrait* étendre cette fonction pour a négatif (mais ce n'est pas la définition d'exponentielle), c'est pour b entier positif et b = (1/3), (1/5)... sinon il n'y a pas de racine réelle pour 0.3, ou 2.1.

Pour tes exemples :

- si tu tapes -1.1^(1/3) ça marche... ben oui, mais si tu tapes (-1.1)^(1/3), en faisant attention a la priorité des opérateur, tu obtiens bien NaN

- si tu fait Pow(1.1, 0.3333333333333331), évidemment que ça marche, le nombre que tu élève est positif.

Non, Math.Pow n'est pas buggée, rassure toi.

Les commentaires anonymes sont désactivés

About FREMYCOMPANY

François REMY est un jeune développeur belge plein d'entrain qui traite surtout des technologies du web et de DotNet dans ses articles.


Les 10 derniers blogs postés

- [SharePoint] Les sessions TechDays 2012… par Le blog de Patrick [MVP SharePoint] le il y a 5 heures et 3 minutes

- TechDays Paris 2012 : Session pleinière jour 3 par Blog Technique de Romelard Fabrice le 02-09-2012, 11:01

- Mishra Reader : un lecteur RSS très Zune Style en Open Source ! par Cyril Sansus le 02-09-2012, 08:28

- [framework 4] Les Tasks et le Thread UI par Fathi Bellahcene le 02-09-2012, 00:33

- Workflow Foundation 3 a un pied dans la tombe par Blog de Jérémy Jeanson le 02-08-2012, 22:15

- TechDays Paris 2012 : Nouvelles tendances du poste de travail - Bring Your own PC par Blog Technique de Romelard Fabrice le 02-08-2012, 19:42

- TechDays Paris 2012 : System Center Service Manager 2012 Vue d’ensemble par Blog Technique de Romelard Fabrice le 02-08-2012, 17:32

- TechDays Paris 2012 : Pleinière second jour par Blog Technique de Romelard Fabrice le 02-08-2012, 16:23

- TechDays Paris 2012 : Retour d'expérience sur la mise en place d'un Cloud Privé par Blog Technique de Romelard Fabrice le 02-08-2012, 16:04

- TechDays Paris 2012 : Comment SharePoint a sauvé mes TechDays par Blog Technique de Romelard Fabrice le 02-07-2012, 23:59




Search

Go

Ce blog

Abonnements