Show / Hide Table of Contents

MSDN.WhiteKnight - Stack Overflow answers

Ответ на "Исключение деления на ноль C#"

Answer 1019768

Link

Никак, потому что исключения нет. Деление на ноль для double вместо исключения выдает специальное значение (Infinity или NaN):

https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/arithmetic-operators#floating-point-arithmetic-overflow

Arithmetic operations with the float and double types never throw an exception. The result of arithmetic operations with those types can be one of special values that represent infinity and not-a-number

double a = 1.0 / 0.0;
Console.WriteLine(a);                    // output: Infinity
Console.WriteLine(double.IsInfinity(a)); // output: True

Console.WriteLine(double.MaxValue + double.MaxValue); // output: Infinity

double b = 0.0 / 0.0;
Console.WriteLine(b);                // output: NaN
Console.WriteLine(double.IsNaN(b));  // output: True

Но для отлова деления на ноль в общем случае это использовать нельзя, так как эти же значения могут говорить о переполнении или, скажем, о конвертации в double непредставимого в нем битового значения. Так что только проверка делителя перед делением.

Конкретно для Windows на архитектурах x86/x86-64 можно включить аппаратное исключение при делении на ноль с помощью _controlfp_s:

using System;
using System.Runtime.InteropServices;

namespace ConsoleApplication1
{
    class Program
    {
        /* msvcrt.dll - недокументированная версия Microsoft CRT, поставляемая с Windows.
        Можно вместо нее взять CRT из конкретной версии Visual C++ Redistributable, например
        msvcr110.dll для Visual C++ 2012 */
        [DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        static extern uint _controlfp_s(ref uint _CurrentState, uint _NewValue, uint _Mask);

        const uint _EM_ZERODIVIDE = 0x00000008;
        const uint _MCW_EM = 0x0008001f;

        static bool EnableFloatingPointTrap()
        {
            uint control_word = 0;
            uint err = _controlfp_s(ref control_word, 0, 0);
            if (err != 0) return false;

            //снимаем флаг, маскирующий исключение при делении на ноль
            uint control_word_new = control_word & ~_EM_ZERODIVIDE;
            err = _controlfp_s(ref control_word, control_word_new, _MCW_EM);
            if (err != 0) return false;

            return true;
        }

        static void Main(string[] args)
        {
            EnableFloatingPointTrap();
            double x = 0.0;
            double y = 1.0 / x; //System.DivideByZeroException
            Console.WriteLine(y);

            Console.ReadKey();

        }
    }  
}

Однако делать так не рекомендуется, так как неизвестно, как поведет себя CLR, если поменять флаги процессора на неожиданные для нее значения. Кроме того, другой код может вернуть назад значение флага.


Content is retrieved from StackExchange API.

Auto-generated by ruso-archive tools.

Back to top Stack Overflow answers (published from sources in GitHub repository). Copyright (c) 2020, MSDN.WhiteKnight. Content licensed under BSD 3-Clause License.
Generated by DocFX