F# 中未抛出 System.ArithmeticException

发布于 2024-10-14 03:41:46 字数 335 浏览 7 评论 0原文

考虑以下代码,

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 上引发异常吗?

Consider the following code

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

It produces both Infinity and NaN. In both cases I want to have an exception thrown (for debuging purposes).

I use Visual Studio 2010. I set up Debug/Exceptions.../Common Language Runtime Exceptions/System/System.ArithmeticException to "Thrown", but when running the code, no exception is thrown.

Any idea why and how to throw an exception on NaN or Infinity?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

扮仙女 2024-10-21 03:41:46

正如其他人指出的,您必须明确检查 NaN 条件。如果您想使用一些高级 F# 功能来执行此操作,那么您还可以使用计算表达式。

可以定义一个构建器,在使用 let! 绑定值时自动检查 Nan。然后你可以写这样的内容:

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

As others noted, you'll have to check for the NaN condition explicitly. If you wanted to do this using some advanced F# features, then you could also use computation expressions.

It is possible to define a builder that automatically checks for Nan when you bind value using let!. Then you could write something like:

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 }

This may be too complicated mechanism for just simple checks, but I find it quite nice. The definition of the computation builder looks like this (you'll need to add While, For and some others to support all language constructs):

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()
海的爱人是光 2024-10-21 03:41:46

如果您想要算术异常,请尝试将整数除以零。 System.Double 类型(F# 中的float)在设计上不会引发异常(所有异常情况均以 NaN 结束)。

来自MSDN 文档

浮点运算符,
包括赋值运算符,做
不抛出异常。相反,在
特殊情况的结果
浮点运算为零,
无穷大,或 NaN...


更新:如果您希望在 InfinityNaN 的情况下抛出异常,我会提供 < a href="https://stackoverflow.com/questions/4782891/system-arithmeticexception-not-thron-in-f/4782960#4782960">与 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

只是另一种选择。

If you want an arithmetic exception, try dividing an integer by zero. The System.Double type (float in F#) by design does not throw exceptions (all exceptional circumstances end up at NaN).

From the MSDN docs:

The floating-point operators,
including the assignment operators, do
not throw exceptions. Instead, in
exceptional situations the result of a
floating-point operation is zero,
infinity, or NaN....


Update: If you want exceptions to be thrown in cases of Infinity or NaN, I would offer the same advice as desco and suggest you wrap the methods you want to call.

Unfortunately, I'm not familiar enough with F# to give code examples in your language of choice; but in C# you might do this for example for a sqrt function:

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

Update 2: Yet another option would be to write your own wrapper for the double type itself which does not allow Infinity or NaN values (again, the below is C#—I apologize if this isn't possible in F# in which case I'm giving you absolutely useless advice):

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

Then wherever you're writing code where you don't want to allow Infinity or NaN, use this type rather than double directly.

Just another option.

萌逼全场 2024-10-21 03:41:46

认为,这只有通过在 sin\sqrt 上提供自定义包装器才有可能实现。当前行为记录为 Math.SqrtMath.Sin

think, this is possible only by providing your custom wrappers over sin\sqrt. Current behavior is documented for Math.Sqrt and Math.Sin.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文