1

次のコードを検討してください

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

Infinity と NaN の両方を生成します。どちらの場合も、(デバッグ目的で) 例外をスローしたいと考えています。

Visual Studio 2010 を使用しています。Debug/Exceptions.../Common Language Runtime Exceptions/System/System.ArithmeticException を "Thrown" に設定しましたが、コードを実行しても例外はスローされません。

NaN または Infinity で例外をスローする理由と方法はありますか?

4

3 に答える 3

5

他の人が指摘したように、 NaN 条件を明示的に確認する必要があります。高度な F# 機能を使用してこれを行う場合は、計算式を使用することもできます。

を使用して値をバインドするときに Nan を自動的にチェックするビルダーを定義することができますlet!。次に、次のように書くことができます。

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 }

これは、簡単なチェックを行うには複雑すぎるメカニズムかもしれませんが、非常に優れていると思います。計算ビルダーの定義は次のようになります (すべての言語構造をサポートするにはWhile、およびその他のいくつかを追加する必要があります)。For

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()
于 2011-01-24T15:40:00.170 に答える
3

算術例外が必要な場合は、整数をゼロで割ってみてください。System.Double( F#のfloat) 型は、設計上、例外をスローしません (すべての例外的な状況は最終的に になりますNaN)。

MSDN ドキュメントから:

代入演算子を含む浮動小数点演算子は、例外をスローしません。代わりに、例外的な状況では、浮動小数点演算の結果はゼロ、無限大、または NaN になります....


更新Infinity:またはの場合に例外をスローする場合は、desco と同じアドバイスをNaN提供し、呼び出したいメソッドをラップすることをお勧めします。

残念ながら、私は F# に精通しておらず、選択した言語でコード例を示すことができません。ただし、C# では、たとえば 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;
}

更新 2 : さらに別のオプションは、または値doubleを許可しない型自体の独自のラッパーを作成することです (繰り返しますが、以下は C# です。F# でこれが不可能な場合は申し訳ありませんが、その場合は絶対に提供します)。役に立たないアドバイス):InfinityNaN

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;
    }
}

Infinity次に、またはを許可したくないコードを記述している場合は、直接NaNではなくこの型を使用doubleします。

ちょうど別のオプション。

于 2011-01-24T14:12:45.363 に答える
1

これは、sin\sqrt にカスタム ラッパーを提供することによってのみ可能です。現在の動作は、Math.SqrtおよびMath.Sinについて文書化されています。

于 2011-01-24T14:14:06.940 に答える