In this article

- Overview
- Numeric Types
- Numeric Literals
- Numerical literal type inference
- Numeric Suffixes
- Numeric Conversion
- Arithmetic Operators
- Increment and Decrement Operators

## Overview

C# has predefined numeric types

- Integral (signed & unsigned)

## Numeric Types

- Of the integral types, int and long are first-class citizens and are favored by both C# and the runtime.
- The other integral types are typically used for interoperability or when space efficiency is paramount.
- The
`nint`

and`nuint`

native-sized integer types (introduced in C# 9) are most useful in helping with pointer arithmetic

### Integral Types

#### Signed

C# type | System type | Suffix | Size | Range |
---|---|---|---|---|

sbyte | Sbyte | 8 bits | ||

short | Int16 | 16 bits | ||

int | Int32 | 32 bits | ||

long | Int64 | L | 64 bits | |

nint | IntPtr | 32/64 bits |

1 bit is reserved for the sign

#### Unsigned

C# type | System type | Suffix | Size | Range |
---|---|---|---|---|

byte | Byte | 8 bits | ||

ushort | UInt16 | 16 bits | ||

uint | UInt32 | U | 32 bits | |

ulong | UInt64 | UL | 64 bits | |

unint | UIntPtr | 32/64 bits |

### Real Types

C# type | System type | Suffix | Size | Range |
---|---|---|---|---|

float | Single | F | 32 bits | ± |

double | Double | D | 64 bits | ± |

decimal | Decimal | M | 128 bits | ± |

and`float`

are called floating-point types and are typically used for scientific and graphical calculations.`double`

- The
type is typically used for financial calculations, for which base-10-accurate arithmetic and high precision are required.`decimal`

From .NET 5, there is a 16-bit floating point type called

`Half`

. This is intended mainly for interoperating with graphics card processors and does not have native support in most CPUs. Half is not a primitive CLR type and does not have special language support in C#.

## Numeric Literals

### Integral Literals

*Integral-type*literals can use*decimal*or**hexadecimal**(prefixed with

) notation.**0x**

Example:

```
int x = 127;
long y = 0x7F;
```

- underscore
`_`

anywhere within a numeric literal is allowed for readability sake, For example:

```
int million = 1_000_000;
```

- You can specify the number in
**binary**with

prefix. For example:**0b**

```
int oneThousand = 0b0011_1110_1000; // 1000 in decimal
```

### Summary

system | prefix | Example |
---|---|---|

Decimal | 127 | |

Binary | 0b | 0b0001 |

Hexadecimal | 0x | 0xfff |

### Real Literals

Real literals can use decimal and/or exponential notation, for example:

```
double d = 1.5;
double million = 1E06;
```

## Numerical literal type inference

By default, the compiler infers a numeric literal to be either * double *or an integral type:

- If the literal contains a decimal point or the exponential symbol (E), it is a double.
- Otherwise, the literal’s type is the first type in this list that can fit the literal’s value:
*int*,*uint*,*long*, and*ulong*. For example:

```
Console.WriteLine ( 1.0.GetType()); // Double (double)
Console.WriteLine ( 1E06.GetType()); // Double (double)
Console.WriteLine ( 1.GetType()); // Int32 (int)
Console.WriteLine ( 0xF0000000.GetType()); // UInt32 (uint)
Console.WriteLine (0x100000000.GetType()); // Int64 (long)
```

## Numeric Suffixes

Numeric suffixes explicitly define the type of a literal. Suffixes can be either lowercase or uppercase.

The suffixes U and L are rarely necessary because the uint, long, and *ulong *types can nearly always be either inferred or implicitly converted from int:

```
long i = 5; // Implicit lossless conversion from int literal to long
```

The D suffix is technically redundant in that all literals with a decimal point are

inferred to be double. And you can always add a decimal point to a numeric literal:

```
double x = 4.0;
```

The F and M suffixes are the most useful and should always be applied when specifying float or decimal literals. Without the F suffix, the following line would not compile, because 4.5 would be inferred to be of type double, which has no implicit conversion to float:

```
float f = 4.5F;
```

The same principle is true for a decimal literal:

```
decimal d = -1.23M; // Will not compile without the M suffix.
```

We describe the semantics of numeric conversions in detail in the following section.

## Numeric Conversion

### Converting between integral types

Integral type conversions are implicit when the destination type can represent every possible value of the source type. otherwise, an explicit conversion is required.

### Converting between floating-point types

A float can be implicitly converted to a double given that a double can represent every possible value of a float. The reverse conversion must be explicit.

### Converting between floating-point and integral types

- All integral types can be implicitly converted to all floating-point types.
- The reverse conversion must be explicit.
- When you cast from a floating-point number to an integral type, any fractional portion is truncated;
- no rounding is performed.
- The static class System. Convert provides methods that round while converting between various numeric types.
- implicitly converting a large integral type to a floating-point type preserves magnitude but can occasionally lose precision. This is because floating-point types always have more magnitude than integral types but can have less precision.

```
int i1 = 100000001;
float f = i1; // Magnitude preserved, precision lost
int i2 = (int)f; // 100000000
```

### Decimal conversions

- All integral types can be implicitly converted to the decimal type given that a decimal can represent every possible C# integral-type value.
- All other numeric conversions to and from a decimal type must be explicit because they introduce the possibility of either a value being out of range or precision being lost.

## Arithmetic Operators

The arithmetic operators are defined for all numeric types except the 8- and 16-bit integral types:

Operator | Description |
---|---|

+ | Addition |

– | Subtraction |

* | Multiplication |

/ | Division |

% | Remainder after division |

## Increment and Decrement Operators

The Increment and decrement operators:

increment numeric types by 1.*++*

decrement numeric types by 1.*--*

The operator can either follow or precede the variable, depending on whether you want its value before or after the increment/decrement;

```
int x = 0, y = 0;
Console.WriteLine (x++); // Outputs 0; x is now 1
Console.WriteLine (++y); // Outputs 1; y is now 1
```