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

71
02 июля 2021, 21:20

Как отловить исключение деления на ноль, когда у тебя данные в double хранятся. С Int всё отлично ловит(try...catch естественно). При делении на число равное нулю, ничего не крашится ХД, а хотелось бы. Как верно это дело отловить. If не подойдет)

Answer 1

Никак, потому что исключения нет. Деление на ноль для 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, если поменять флаги процессора на неожиданные для нее значения. Кроме того, другой код может вернуть назад значение флага.

READ ALSO
vk авторизация от имени сообщества

vk авторизация от имени сообщества

Начинаю программировать на C# по этому возможно чего-то просто не могу увидетьРою интернет несколько дней, не могу найти информацию о том...

108
Unity3D Неправильно поворачивается объект

Unity3D Неправильно поворачивается объект

Делаю небольшую игру на Unity и C#Проблема в том, что когда поворачивается объект, вместо поворота он растягивается (Коллайдер тоже)

85
как перевести yii2 на production

как перевести yii2 на production

Я облазил весь интернет в поиске того, как перевести yii2 на продакшинИ практическе везде я видел ответы типа:

140