Содержание
| Тип | SYSTEM псевдоним | Суффикс | Размер | Диапазон |
|---|---|---|---|---|
| Целые числа со знаком (Signed integer) | ||||
| sbyte | SByte | 8 bits | –27 до 27–1 | |
| short | Int16 | 16 bits | –215 до 215–1 | |
| int | Int32 | 32 bits | –231 до 231–1 | |
| long | Int64 | L | 64 bits | –263 до 263–1 |
| Целые числа бес знака (Unsigned integer) | ||||
| byte | Byte | 8 bits | 0 до 28–1 | |
| ushort | UInt16 | 16 bits | 0 до 216–1 | |
| uint | UInt32 | U | 32 bits | 0 до 232–1 |
| ulong | UInt64 | UL | 64 bits | 0 до 264–1 |
| Реальные числа (Real number) | ||||
| float | Single | F | 32 bits | ± (~10–45 до 1038) |
| double | Double | D | 64 bits | ± (~10–324 до 10308) |
| decimal | Decimal | M | 128 bits | ± (~10–28 до 1028) |
Среди целочисленных (integral) типов int и long используются наиболее часто. Остальные применяются для функциональной совместимости или когда действительно необходимы большие числа. Из реальных чисел, float и double, также называемые числами с плавающей точкой (floatingpoint types), обычно используются для научных вычислений. Тип decimal обычно используется в финансовых вычислениях, где необходима десятичная арифметика и высокая точность. Различия между double и decimal приведены в следующей таблице:
| double | decimal | |
|---|---|---|
| Внутреннее представление | двоичное | десятичное |
| Точность | 15-16-значные цифровые данные | 28-29-значные цифровые данные |
| Диапазон | ±(~10–324 до ~10308) | ±(~10–28 to ~1028) |
| Специальные значения | +0, –0, +∞, –∞, NaN | Нет |
| Скорость вычисления | Зависит от процессора | Не зависит от процессора и приблизительно в 10 раз медленнее чем double |
В связи с тем что типы float и double в своем внутреннем представлении являются двоичными, литералы с дробной частью (десятичные) не являются совсем точными:
1 2 3 | float tenth = 0.1f; // Не совсем 0.1 float one = 1f; Console.WriteLine (one - tenth * 10f); // -1.490116E-08 |
По этой причине float и double лучше не использовать для финансовых вычислений, для которых лучше подходит тип decimal, десятичный в своей основе и поэтому более точный для дробных десятичных чисел.
Числовые литералы (Numeric Literals)
Целочисленные литералы (Integral literals) могут использовать десятичную (decimal) или шестнадцатеричную (hexadecimal) запись; шестнадцатеричная обозначается префиксом 0x (например, 0x7f = 127). Реально-числовые литералы также используют десятичную и шестнадцатеричную запись (например, 1E06).
По умолчанию, компилятор определяет тип числовых литералов по следующим критериям: если литерал содержит десятичную точку или знак экспоненты (E) — это double, в противном случае — это int, uint, long, или ulong.
Тип литерала также можно указать с помощью суффиксов, перечисленных в таблице выше. Суффикс ставиться сразу после литерала, например:
1 | decimal d = 3.5M; // M = decimal (регистрозависимо) |
Необходимость в суффиксах U и L возникает крайне редко, т.к. почти всегда типы uint, long, и ulong могут быть либо выведены либо неявно преобразованы из int:
1 | long i = 5; // Скрытое преобразование из int в long |
Суффикс D технически излишен, т.к. все литералы с десятичной точкой приводятся к double. Суффиксы F и M более полезны: они необходимы при написании дробных литералов типа float или decimal. Без суффикса подобные литералы будут считаться типом double, который не преобразуется скрыто к float или decimal.
1 2 | float f = 4.5F; // Без суффикса не скомпилируется decimal d = -1.23M; // Без суффикса не скомпилируется |
Преобразование чисел
Скрытое преобразование целых чисел возможно только когда конечный тип вмещает все возможные значения исходного, в противном случае необходимо явное преобразование:
1 2 3 | int x = 12345; // int - 32-битное число long y = x; // Скрытое преобразование к 64-битному числу short z = (short)x; // Явное преобразование к 16-битному числу |
Преобразование реальных чисел. Число типа float может быть скрыто преобразовано к double, поскольку double способно вместить все возможные значения float. Обратное преобразование должно быть явным. Преобразование между decimal и другими реальными типами должно быть явным.
Преобразование между реальными и целыми числами. Преобразование целых чисел в реальные может быть скрытым, а вот обратное должно быть явным. Преобразование реальных чисел в целые происходит путем отсечения дробной части (без округления). Если необходимо преобразование с округлением, нужно использовать System.Convert класс. Важно помнить, что преобразование больших целых чисел в числа с плавающей точкой сохраняет их величину (magnitude, колличество цифр), но может привести к потере точности (precision):
1 2 3 | int i1 = 100000001; float f = i1; // Величина сохранена, точность потеряна int i2 = (int)f; // 100000000 |
Числовые операторы
Арифметические операторы
Арифметические операторы: + - * / %. Они применимы ко всем числовым типам, корме 8- и 16-битных целочисленных типов.
При делении целых чисел остаток всегда отсекается. При делении на переменную равную нулю возникает ошибка времени исполнения, а при делении на литерал или константу 0 — ошибка времени компиляции.
Оператор % возвращает остаток после деления.
Инкремент и декремент
Операторы инкремента ++ (Incremantal) и декремента — (Decremental) увеличивают и уменьшают (соответственно) числа на 1. Они могут идти до или после переменной, в зависимости от того, когда необходимо изменить переменную: до или после вычисления выражения:
1 2 3 4 | int x = 0; Console.WriteLine (x++); // Выведет 0; x = 1 Console.WriteLine (++x); // Выведет 2; x = 2 Console.WriteLine (--x); // Выведет 1; x = 1 |
Переполнение и оператор check
При выполнении арифметических операций с целыми числами возможно переполнение (Integral overflow) — ситуация, когда полученный результат превышает арифметические пределы типы. Как правило оно происходит тихо: никакие исключения не выбрасываются.
Оператор checked заставляет генерировать ошибку при переполнении (OverflowException). Он воздействует на выражения с операторами ++, —, — (унарный, обозначающий отрицательное число), +, -, *, / и операторами явного приведения между целочисленными типами. Применять его можно либо к одному выражению, либо к блоку:
1 2 3 4 5 6 7 | int a = 1000000, b = 1000000; int c = checked (a * b); // Применяется к одному выражению checked // Применяется к блоку выражений { c = a * b; ... } |
В последнем случае, если для какого-либо выражения или блока необходимо отключить проверку переполнения, аналогичным способом необходимо использовать оператор unchecked.
Побитовые (поразрядные, bitwise) операторы
Каждый целочисленный тип может быть представлен в виде последовательности бит:
1 2 3 4 5 | int a = 0; // 00000000 int a = 1; // 00000001 int a = 2; // 00000010 int a = 10; // 00001010 int a = 255; // 11111111 |
Битовые операторы применяются последовательно к каждой паре соответствующих битов своих операндов. Результатом будет значение того же типа, что и операнды, каждый бит которого есть результат применения соответствующего побитового оператора.
К побитовым операторам относятся:
- И —
&— устанавливает (в значение 1) только те биты, которые установлены (имеют значение 1) в обоих операндах, остальные биты выключаются (устанавливаются в 0) - ИЛИ —
|— устанавливает те биты которые установлены либо в одном, либо в другом операнде - ИСКЛЮЧАЮЩЕЕ ИЛИ —
^— устанавливает только те биты, которые установлены либо в одном, либо в другом операнде, но не в обоих одновременно - ОТРИЦАНИЕ —
~— унарный оператор: устанавливает те биты, которые не установлены в операнде - СДВИГ ВЛЕВО —
<<— сдвигает биты левого операнда влево на число позиций, равное второму операнду - СДВИГ ВПРАВО —
>>— сдвигает биты левого операнда вправо на число позиций, равное второму операнду
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | int a = 5; // 00000101 int b = 6; // 00000110 Console.WriteLine ( a & b ); // 00000100 == 4 Console.WriteLine ( a | b ); // 00000111 == 7 Console.WriteLine ( a ^ b ); // 00000011 == 3 Console.WriteLine ( = ~ a ); // 11111010 == 250 int a = 43; // 00101011 Console.WriteLine ( a >> 1 ); // 00010101 == 21 Console.WriteLine ( a >> 2 ); // 00001010 == 10 Console.WriteLine ( a >> 3 ); // 00000101 == 5 Console.WriteLine ( a >> 5 ); // 00000001 == 1 int a = 5; // 00000101 Console.WriteLine ( a << 1 ); // 00001010 == 10 Console.WriteLine ( a << 2 ); // 00010100 == 20 Console.WriteLine ( 2 << 3 ); // 00101000 == 40 |
n бит равносилен (для положительных чисел) умножению на 2n.Операции с 8-битные и 16-битные целыми числами
8-битные и 16-битные целые числа (byte, sbyte, short, ushort) не имеют собственных операторов, поэтому C# неявно преобразовывает их в большие типы при необходимости. В связи с этим при компиляции может возникнуть ошибка, если результату попытаться снова назначить младший тип:
1 2 | short x = 1, y = 1; short z = x + y; // Ошибка времени компиляции |
В этом примере x и y скрыто преобразуются в int, чтоб над ними можно было выполнить сложение. Результат в связи с этим тоже будет иметь тип int, который не может быть скрыто преобразован обратно в short (т.к. это может привести к потере данных). Чтобы избежать ошибки, необходимо использовать явное приведение к типу:
1 | short z = (short) (x + y); |
Операции над числами с плавающей точкой
Типы с плавающей точкой (в отличие от целочисленных) имеют ряд специальных значений, которые ведут себя по особенному в ряде случаев. Этими специальными значениями являются:
NaN(Not a Number)+∞–∞–0
Деление ненулевого значения на ноль дает бесконечность:
1 2 3 4 | Console.WriteLine ( 1.0 / 0.0); // Бесконечность Console.WriteLine (–1.0 / 0.0); // -Бесконечность Console.WriteLine ( 1.0 / –0.0); // -Бесконечность Console.WriteLine (–1.0 / –0.0); // Бесконечность |
Деление ноль на ноль и вычитание бесконечности из бесконечности дает NaN:
1 2 | Console.Write ( 0.0 / 0.0); // NaN Console.Write ((1.0 / 0.0) – (1.0 / 0.0)); // NaN |
При использовании оператора сравнения ==, значение NaN никогда не будет равно никакому другому значению, в том числе другому значению NaN. Для проверки значения на равенство NaN нужно использовать методы float.IsNaN и double.IsNaN:
1 2 | Console.WriteLine (0.0 / 0.0 == double.NaN); // False Console.WriteLine (double.IsNaN (0.0 / 0.0)); // True |
Однако, при использовании метода object.Equals два NaN значения будут равны:
1 | bool isTrue = object.Equals (0.0/0.0, double.NaN); |
Преобразование чисел в строку, форматные строки
Числовые типы определяют экземплярный метод ToString, позволяющий преобразовать число в строку. В качестве дополнительного параметра метод может принимать форматные строки. Подробно этот метод и форматные строки рассмотрены в разделе, посвященном форматированию и преобразованию строк. Ниже будут перечислены стандартные и специальные форматные строки для чисел.
Стандартные форматные строки для чисел
| Символ | Значение | Пример | Результат | Примечание |
|---|---|---|---|---|
| G или g | Общий (general) формат | 1.2345, «G» 0.00001, «G» 0.00001, «g» 1.2345, «G3» 12345, «G3» | 1.2345 1E-05 1e-05 1.23 1.23E04 | Перключается на экспоненциальную запись для очень маленьких и больших чисел. Цифра ограничивает точность (количество цифр) |
| F | Формат с фиксированной точкой | 2345.678, «F2» 2345.6, «F2» | 2345.68 2345.60 | Цифра указывает сколько знаков оставить после запятой |
| N | Формат с фиксированной точкой и разделителем групп | 2345.678, «N2» 2345.6, «N2» | 2,345.68 2,345.60 | Тоже самое что и F, но с разделением групп (тысяч) |
| D | Заполнение ведущими нулями | 123, «D5» 123, «D1» | 00123 123 | Только для целых типов. Цифра указывает до какой длины дополнять, усечение не происходит |
| E или e | Экспоненциальная запись | 56789, «E» 56789, «e» 56789, «E2» | 5.678900E+004 5.678900e+004 5.68E+004 | Цифра указывает точность (по умолчанию — 6) |
| C | Денежное значение | 1.2, «C» 1.2, «C4» | $1.20 $1.2000 | Цифра указывает количество знаков после запятой |
| P | Процент | .503, «P» .503, «P0» | 50.30 % 50 % | Цифра указывает количество знаков после запятой |
| X или x | Шестнадцатеричный формат | 47, «X» 47, «x» 47, «X4» | 2F 2f 002F | X — верхний регистр, x — нижний регистр |
| R | Округление | 1f / 3f, «R» | 0.333333343 |
Указание иной форматной строки, пустой строки или null эквивалентно «G».
Специальные форматные строки для чисел
| Символ | Значение | Пример | Результат | Примечание |
|---|---|---|---|---|
| # | Заполнитель для цифр | 12.345, «.##» 12.345, «.####» | 12.35 12.345 | |
| 0 | Заполнитель для нуля | 12.345, «.00» 12.345, «.0000» 99, «000.00» | 12.35 12.3500 099.00 | |
| . | Десятичная точка | |||
| , | Разделитель групп | 1234, «#,###,###» 1234, «0,000,000» | 1,234 0,001,234 | |
| , | Коэффициент | 1000000, «#,» 1000000, «#,,» | 1000 1 | |
| % | Процентная запись | 0.6, «00%» | 60% | |
| E0, e0, E+0, e+0 E-0, e-0 | Экспоненциальная запись | 1234, «0E0» 1234, «0E+0» 1234, «0.00E00» 1234, «0.00e00» | 1E3 1E+3 1.23E03 1.23e03 | |
| / | Скобка для литерального символа | 50, @»\#0″ | #50 | Используется в сочетании с префиксом @ в строках или можно применять // |
| ‘xx»xx’ | Скобка для литеральной строки | 50, «0 ‘…'» | 50 … | |
| ; | Разделитель секций | 15, «#;(#);zero» −5, «#;(#);zero» 0, «#;(#);zero» | 15 (5) zero | |
| другой символ | Литерал | 35.2, «$0 . 00c» | $35 . 20c |
Преобразование строки в число, NumberStyles
Преобразование строки в число можно осуществить с помощью статических методов Parse и TryParse. Подробно эти методы рассмотрены в разделе, посвященном форматированию и преобразованию строк.
Оба метода могут принимать enum NumberStyles, определяющий как строка читается при преобразовании в числовой тип (они позволяют указывать такие аспекты, как могут ли встречаться во входной строке круглые скобки или символ валюты):
1 2 3 4 5 | int error = int.Parse ("(2)"); // Генерация исключения int minusTwo = int.Parse ("(2)", NumberStyles.Integer | NumberStyles.AllowParentheses); // OK decimal fivePointTwo = decimal.Parse ("£5.20", NumberStyles.Currency, CultureInfo.GetCultureInfo ("en-GB")); |
Комбинируемые члены NumberStyles:
AllowLeadingWhite— допускает наличие в начале входной строки пробеловAllowTrailingWhite— допускает наличие в конце входной строки пробеловAllowLeadingSign— допускает наличие в начале входной строки символовAllowTrailingSign— допускает наличие в конце входной строки символовAllowParentheses— допускает наличие во входной строке скобокAllowDecimalPoint— допускает наличие во входной строке десятичной точкиAllowThousands— допускает наличие во входной строке разделителя разрядовAllowExponent— допускает наличие во входной строке экспонентыAllowCurrencySymbol— допускает наличие во входной строке символа валютAllowHexSpecifier— допускает наличие во входной строке символа шестнадцатиричной записи
Составные члены NumberStyles:
None— любые символы кроме цифр в входной строке не допустимыInteger— допустимы символы для целых чиселFloat— допустимы символы для чисел с плавающей точкойNumber— допустимы символы для любых чиселHexNumber— допустимы символы для шестнадцатиричной записиCurrency— допустимы символы для валютыAny— допустимы любые символы
Если входная строка содержит символы отличные от цифр, а NumberStyles не методу не передан, будет сгенерировано исключение.

