# 2. Numeric Types

## 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

1 bit is reserved for the sign

### Real Types

• float and double are called floating-point types and are typically used for scientific and graphical calculations.
• The decimal type is typically used for financial calculations, for which base-10-accurate arithmetic and high precision are required.

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 0x) notation.
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 0b prefix. For example:
  int oneThousand = 0b0011_1110_1000; // 1000 in decimal


### 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:

## 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