Содержание
Тип | 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
не методу не передан, будет сгенерировано исключение.