Question

Considérez le code suivant

let a = 5. / 0.
let b = sin a
let c = sqrt(-5.)

Il produit à la fois infini et NaN. Dans les deux cas, je veux avoir une exception levée (à des fins debug).

J'utilise Visual Studio 2010. Je Configuration Debug / Exceptions ... / Common Language Runtime Exceptions / Système / System.ArithmeticException à "Jeté", mais lors de l'exécution du code, pas d'exception est levée.

Toute idée pourquoi et comment jeter une exception sur NaN ou Infinity?

Était-ce utile?

La solution

Comme d'autres ont noté, vous devrez vérifier la condition NaN explicitement. Si vous vouliez faire utiliser certaines fonctions F # avancées, vous pouvez également utiliser des expressions de calcul.

Il est possible de définir un constructeur qui vérifie automatiquement pour Nan lorsque vous le liez valeur à l'aide let!. Ensuite, vous pouvez écrire quelque chose comme:

check { let! a = 5. / 0.    // 'a' is checked here
        let! b = sin a      // 'b' is checked here
        let c = sqrt(-5.)   // 'c' is not checked (no 'let!')
        return a, b, c }

Cela peut être trop compliqué pour le mécanisme des contrôles de simples, mais je trouve ça assez agréable. La définition du calcul constructeur se présente comme suit (vous aurez besoin d'ajouter While, For et quelques autres pour soutenir toutes les constructions de langage):

open System

type CheckedBuilder() = 
  member x.Bind(v:float, f) = 
    if Double.IsNaN(v) |> not then f v
    else raise (new ArithmeticException())
  member x.Return(v) = v

let check = CheckedBuilder()

Autres conseils

Si vous voulez une exception arithmétique, essayez division d'un entier par zéro. Le type de System.Double (de float en F #) par la conception ne jette pas des exceptions (toutes les circonstances exceptionnelles finissent à NaN).

De documentation MSDN:

Les opérateurs à virgule flottante, y compris les opérateurs d'affectation, faire pas jeter des exceptions. Au lieu de cela, dans des situations exceptionnelles, le résultat d'un opération en virgule flottante est égale à zéro, infini ou NaN ....


Mise à jour : Si vous voulez des exceptions à être jetés dans les cas de Infinity ou NaN, je l'offre même conseil que desco et proposez-vous envelopper les méthodes que vous voulez appeler.

Malheureusement, je ne suis pas assez familier avec F # pour donner des exemples de code dans la langue de votre choix; mais en C # vous pouvez le faire par exemple pour une fonction sqrt:

public static double CheckedSqrt(double x)
{
    double sqrt = Math.Sqrt(x);
    if (double.IsNaN(sqrt))
    {
        throw new ArithmeticException("The square root of " + x + " is NaN.");
    }

    return sqrt;
}

Mise à jour 2 : Une autre option serait d'écrire votre propre emballage pour le type de double lui-même qui ne permet pas les valeurs de Infinity ou NaN (encore une fois, le ci-dessous est C # -I excuse si ce n » t possible en F # dans ce cas, je vous donne des conseils absolument inutile):

public struct CheckedDouble // : IEquatable<CheckedDouble>, etc.
{
    double m_value;

    public CheckedDouble(double value)
    {
        if (double.IsInfinity(value) || double.IsNaN(value))
        {
            throw new ArithmeticException("A calculation resulted in infinity or NaN.");
        }

        m_value = value;
    }

    public static implicit operator CheckedDouble(double value)
    {
        return new CheckedDouble(value);
    }

    public static implicit operator double(CheckedDouble checkedDouble)
    {
        return checkedDouble.m_value;
    }
}

Alors où que vous soyez le code d'écriture où vous ne voulez pas permettre Infinity ou NaN, utiliser ce type plutôt que double directement.

Juste une autre option.

penser, cela est possible seulement en fournissant vos emballages personnalisés sur le péché \ sqrt. comportement actuel est documenté Math.sqrt et Math.sin .

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top