In .NET (as in many other languages), there is a separation between integer types and rational types, so I will separate my explanation of these types into these two categories.

# Whole Types

There are several integer types, again they can be separated into two groups, those that accept negative values, and those that do not accept negative values.

Accept Negatives (have sign): `Int32`

is the most common, but we have others: `Int16`

, `Int64`

(no `Long`

, but alias `long`

in C #, which is the same as `Int64`

) and `SByte`

.

```
│ Tipo ║ Bits ║ Mínimo ║ Máximo ║ Alias C# ║ Literal │
╞═══════╬══════╬════════════════════════════╬═══════════════════════════╬══════════╬═════════╡
│ SByte ║ 8 ║ -128 ║ 127 ║ sbyte ║ │
│ Int16 ║ 16 ║ -32768 ║ 32767 ║ short ║ │
│ Int32 ║ 32 ║ -2.147.483.648 ║ 2.147.483.647 ║ int ║ 0 │
│ Int64 ║ 64 ║ -9.223.372.036.854.775.808 ║ 9.223.372.036.854.775.807 ║ long ║ 0L │
└───────╨──────╨────────────────────────────╨───────────────────────────╨──────────╨─────────┘
```

The letters that appear in the literals can be uppercase or lowercase: `0L`

is the same as `0l`

.

Accept positive values only (no sign):

```
│ Tipo ║ Bits ║ Mínimo ║ Máximo ║ Alias C# ║ Literal │
╞════════╬══════╬════════╬════════════════════════════╬══════════╬═════════╡
│ Byte ║ 8 ║ 0 ║ 255 ║ byte ║ │
│ UInt16 ║ 16 ║ 0 ║ 65535 ║ ushort ║ │
│ UInt32 ║ 32 ║ 0 ║ 4.294.967.295 ║ uint ║ 0U │
│ UInt64 ║ 64 ║ 0 ║ 18.446.744.073.709.551.615 ║ ulong ║ 0UL │
└─────═──╨──────╨────────╨────────────────────────────╨──────────╨─────────┘
```

The letters that appear in the literals can be uppercase or lowercase: `0UL`

is the same as `0ul`

.

In terms of the use of these types, there is no major difference in performance in the use of local variables or method parameters. Generally, the type `Int32`

( `int`

) is used for these uses, unless the expected values exceed the limits of int, in which case `Int64`

( `long`

) is used.

While `Byte`

( `byte`

) is only used even to work with binary data, I have never seen it being used in any code other than this.

The other types are usually only used in very long `struct`

or `class`

data structures, or else in arrays, so that they occupy less memory ... but this would only make sense even in heavily used structures, or even very large arrays of the order of millions or even billions of items.

In addition to all this, I see unsigned types (those that only accept positives) to be used in bitwise operations (called commonly bitwise), because of the ease of working with all bits of the same, which is more difficult when there is the signal bit.

# Rational Types

There are only 3 of these in .NET: `Single`

, `Double`

and `Decimal`

.

```
│ Tipo ║ Single ║ Double ║ Decimal │
╞══════════╬═══════════════╬═══════════════════════════╬═════════════════════════════════════════╡
│ Alias C# ║ float ║ double ║ decimal │
│ Mínimo ║ -3.402823e+38 ║ -1.7976931348623157e+308 ║ -79.228.162.514.264.337.593.543.950.335 │
│ Máximo ║ 3.402823e+38 ║ 1.7976931348623157e+308 ║ 79.228.162.514.264.337.593.543.950.335 │
│ Literal ║ 0f ║ 0.0 ou 0d ║ 0m │
│ Base Exp.║ 2 ║ 2 ║ 10 │
└──────────╨───────────────╨───────────────────────────╨─────────────────────────────────────────┘
```

The letters that appear in the literals can be uppercase or lowercase: `0M`

is the same as `0m`

.

Base types 2 ( `Single`

and `Double`

) are operated by instructions from the processor itself, in a
unit called floating-point unit (FPU) ... and that in current processors
are so optimized that math operations with floating points arrive
to be as fast as whole types.

The types `Single`

and `Double`

are used when there is no correspondence
with decimal numbers in a fraction. Examples: calculations involving the
physics, used in engineering or simulations made in games, use these types.

In terms of performance, the types `Single`

and `Double`

are the same on machines
current, because the FPU converts both internally to 80-bits. So the only advantage
real in using `Single`

is in terms of memory usage.

Type `Decimal`

exists to support operations that must match
with decimal fractions of the real world, when working with values
money ... including, I think `M`

literal comes from money (but this I am
speculating).

The type `Decimal`

has 128 bits, of which 96 are used to represent the internal value
called the mantissa, and the others are used to indicate a base divider 10 ...
is practically an exponent, just as it exists for base 2, except that in base 10
and only negatives. Therefore, `Decimal`

is not able to represent numbers
as large as `Single`

and `Double`

(since these two accept positive exponents).
In compensation, the% type of% has an absurdly greater precision.

In terms of performance, the type `Decimal`

is very poor compared to the types
base-2, since all mathematical operations are done in the Arithmetic logic unit (ALU),
and are therefore subdivided into several stages of calculations independently of the operation
being made.