簡體   English   中英

F#中未引發System.ArithmeticException

[英]System.ArithmeticException not thrown in F#

考慮以下代碼

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

它同時產生Infinity和NaN。 在這兩種情況下,我都希望引發一個異常(出於調試目的)。

我使用Visual Studio2010。我將Debug / Exceptions / Common Language Runtime Exceptions / System / System.ArithmeticException設置為“ Thrown”,但是在運行代碼時不會引發任何異常。

知道為什么以及如何在NaN或Infinity上引發異常嗎?

如其他人所述,您必須顯式檢查NaN條件。 如果您想使用某些高級F#功能來執行此操作,則還可以使用計算表達式。

可以定義一個構建器,該構建器在使用let!綁定值時自動檢查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 }

對於簡單的檢查來說,這可能是太復雜的機制,但是我覺得它很好。 計算生成器的定義如下所示(您需要添加WhileFor和其他一些語言來支持所有語言構造):

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()

如果要算術異常,請嘗試將整數除以零。 System.Double類型(按F# float )在設計上不會引發異常(所有異常情況最終都以NaN結尾)。

MSDN文檔

浮點運算符(包括賦值運算符)不會引發異常。 相反,在特殊情況下,浮點運算的結果為零,無窮大或NaN。


更新 :如果您希望在InfinityNaN情況下引發異常,我將提供與desco相同的建議,並建議您包裝要調用的方法。

不幸的是,我對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類型本身編寫自己的包裝器,該包裝器不允許使用InfinityNaN值(再次,以下是C#,對於在F#中無法實現此方法,我深表歉意。給您絕對無用的建議):

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

然后,在您不想允許InfinityNaN地方編寫代碼,請使用此類型,而不要直接使用double

只是另一個選擇。

認為,只有通過在sin \\ sqrt上提供自定義包裝,才有可能。 當前行為記錄在Math.SqrtMath.Sin中

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM