2. Numeric Types

In this article

  1. Overview
  2. Numeric Types
    1. Integral Types
      1. Signed
      2. Unsigned
    2. Real Types
  3. Numeric Literals
    1. Integral Literals
    2. Summary
    3. Real Literals
  4. Numerical literal type inference
  5. Numeric Suffixes
  6. Numeric Conversion
    1. Converting between integral types
    2. Converting between floating-point types
    3. Converting between floating-point and integral types
    4. Decimal conversions
  7. Arithmetic Operators
  8. 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# typeSystem typeSuffixSizeRange
sbyteSbyte8 bits-2^7 \quad to \quad 2^7 - 1
shortInt1616 bits-2^{15} \quad to \quad 2^{15} - 1
intInt3232 bits-2^{31} \quad to \quad 2^{31} - 1
longInt64L64 bits-2^{63} \quad to \quad 2^{63} - 1
nintIntPtr32/64 bits

1 bit is reserved for the sign

Unsigned

C# typeSystem typeSuffixSizeRange
byteByte8 bits0 \quad to \quad 2^8 - 1
ushortUInt1616 bits0 \quad to \quad 2^{16} - 1
uintUInt32U32 bits0 \quad to \quad 2^{32} - 1
ulongUInt64UL64 bits0 \quad to \quad 2^{64} - 1
unintUIntPtr32/64 bits

Real Types

C# typeSystem typeSuffixSizeRange
floatSingleF32 bits±(~10^{-45} \quad to \quad 10^{38})
doubleDoubleD64 bits±(~10^{-324} \quad to \quad 10^{308})
decimalDecimalM128 bits±(~10^{-324} \quad to \quad 10^{308})
  • 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

Summary

systemprefixExample
Decimal127
Binary0b0b0001
Hexadecimal0x0xfff

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:

OperatorDescription
+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

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s