2014-09-20 3 views
1

Так что вопрос:Как узнать значение переполнения без повторяющихся на время выполнения OverflowException

Учитывая нативный целочисленный тип, который представляет наибольшее возможное число в данном компилятором (? Языке), например ulong в C#, как вы обнаруживаете, что входная строка, представляющая число, переполняет наибольшее значение, которое представляется этим типом, не возвращаясь к проверенному контексту и времени выполнения OveflowException?

Очевидно, что C# компилятор может обнаружить постоянные интегральные перетоки:

ulong l = 18446744073709551615; //ok 
ulong l = 18446744073709551616; //compile time error: Integral constant is too large. 

является составителем с помощью выполнения OverflowException (или эквивалент) под капотом? Если да, существует ли способ сделать это без повторения исключения времени выполнения или создания числового типа, который может содержать большие числа, такие как System.Numeric.BigInt? Стоит отметить, что BigInt не имеет встроенной поддержки в C#, как следующее сообщение об ошибке во время компиляции, хотя интегральная постоянная хорошо внутри диапазона типа по:

BigInt i = 18446744073709551616; //compile time error: Integral constant is too large. 
+1

Заключительное исключение, например 'TryParse', также считается no-no? –

+1

Вы можете взглянуть на ['UInt64.TryParse'] (http://referencesource.microsoft.com/#mscorlib/system/number.cs), в пути нет' try-catch'. Однако я не знаю, как использует компилятор. –

+2

@InBetween: «Если я не ошибаюсь, TryParse просто обертывает Parse, который генерирует исключение во время выполнения». Нет. Это исключение. В этом-то и дело. – spender

ответ

1

Would что-то вроде этого графа в качестве решения?

string s1 = "18446744073709551616"; 
string s2 = ulong.MaxValue.ToString(); 
// assuming s1 contains digits only and no leading zeros 
if(
    s1.Length > s2.Length || 
    s1.Length == s2.Length && string.CompareOrdinal(s1, s2) > 0 
) 
    Console.WriteLine("overflow"); 
+0

Ницца :) Мы думали о том, чтобы делать это таким образом, но это казалось взломом больше всего на свете. Мы предпочли бы какой-то умный математический трюк, но, похоже, нет. – InBetween

+0

@InBetween Ну, более правильным способом было бы реализовать собственный парсер. См. [NumberToUInt64] (http://referencesource.microsoft.com/mscorlib/a.html#8b55e44a1e338fc4) – AlexD

1

компилятор скорее всего, просто разбирает ввод одной цифры в то время, с кодом, подобным ulong.Parse, но, очевидно, адаптированного к задаче.

Способ ulong.Parse решает, что он переполнен достаточно прост, но вам нужно знать, как анализируются целые числа. ulong.Parse анализирует входной символ за раз. Он поддерживает результат ulong, и для каждого символа он умножает результат на 10, затем добавляет значение символа (от 0 до 9), и он продолжает делать это до тех пор, пока не закончится вход или результат не переполнится.

Есть две проверки переполнения, потому что есть две вещи, которые могут переполняться: умножение на 10 и добавление. Чтобы проверить, что умножение не будет переполняться, текущий результат сравнивается с 1844674407370955161. Если результат больше этого, и все еще остаются цифры, алгоритм выходит из строя, переполняя отчет. Обратите внимание, что это число совпадает с ulong.MaxValue с удаленной последней цифрой, что делает его самым большим целым числом, которое можно умножить на 10 без переполнения.

Далее необходимо проверить, не произойдет ли переполнение числа от 0 до 9. Он делает это, сначала добавляя номер, а затем проверяя, был ли результат уменьшенным вместо увеличения. Это работает из-за того, как добавление реализовано внутри процессоров; в основном верхний бит результата отбрасывается, потому что он не подходит.

И все, действительно. Если символы заканчиваются без отключения какой-либо из двух проверок выше, число успешно анализируется, иначе это переполнение.

Смежные вопросы