Numeric Types

C# has the following predefined numeric types.

C# type

System type

Suffix

Size

Range

Integral—signed

   

sbyte

SByte

 

8 bits

–27 to 27–1

short

Int16

 

16 bits

–215 to 215–1

int

Int32

 

32 bits

–231 to 231–1

long

Int64

L

64 bits

–263 to 263–1

Integral—unsigned

   

byte

Byte

 

8 bits

0 to 28–1

ushort

UInt16

 

16 bits

0 to 216–1

uint

UInt32

U

32 bits

0 to 232–1

ulong

UInt64

UL

64 bits

0 to 264–1

Real

    

float

Single

F

32 bits

±( ~10–45 to 1038)

double

Double

D

64 bits

±( ~10–324 to 10308)

decimal

Decimal

M

128 bits

±( ~10–28 to 1028)

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

Of the real number types, float and double are called floating-point types and are typically used for scientific calculations. The decimal type is typically used for financial calculations, where base-10-accurate arithmetic and high precision are required.[1]

Numeric Literals

Integral literals can use decimal or hexadecimal notation; hexadecimal is denoted with the 0x; prefix. For example:

	int x = 127;
	long y = 0x7F;

Real literals can use decimal and/or exponential notation. For example:

	double d = 1.5;
	double million = 1E06;

Numeric 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, ulong, and long.

For example:

	Console.Write(       1.0.GetType( ));  // Double (double)
	Console.Write(      1E06.GetType( ));  // Double (double)
	Console.Write(         1.GetType( ));  // Int32 (int)
	Console.Write(0xF0000000.GetType( ));  // UInt32 (uint)

Numeric suffixes

Numeric suffixes explicitly define the type of a literal (suffixes can be either lower- or uppercase):

Category

C# type

Notes

Example

F

float

 

float f = 1.0F;

D

double

 

double d = 1D;

M

decimal

 

decimal d = 1.0M;

U

uint or ulong

Combinable with L

uint i = 1U;

L

long or ulong

Combinable with U

ulong i = 1UL;

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 x = -1.23M;   // Will not compile without
	                      // the M suffix.

The semantics of numeric conversions are described in detail in the following section.

Numeric Conversions

Integral to integral conversions

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

Floating-point to floating-point conversions

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

Floating-point to integral conversions

All integral types may be implicitly converted to all floating point numbers:

	int i = 1;
	float f = i;

The reverse conversion must be explicit:

	int i2 = (int)f;

Warning

When you cast from a floating-point number to an integral, 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 may occasionally lose precision. This is because floating-point types always have more magnitude than integral types, but they may have less precision. Rewriting our example with a larger number demonstrates:

	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 because a decimal can represent every possible C# integral value. All other numeric conversions to and from a decimal type must be explicit.

Arithmetic Operators

The arithmetic operators (+, -, *, /, %) are defined for all numeric types except the 8- and 16-bit integral types:

	+  Addition
	-  Subtraction
	*  Multiplication
	/  Division
	%  Remainder after division

Increment and Decrement Operators

The increment and decrement operators (++, --) increment and decrement numeric types by one. The operator can either precede or follow the variable, depending on whether you want the variable to be updated before or after the expression is evaluated. For example:

	int x = 0;
	Console.WriteLine (x++);   // outputs 0; x is now 1
	Console.WriteLine (++x);   // outputs 2; x is now 2
	Console.WriteLine (--x);   // outputs 1; x is now 1

Specialized Integral Operations

Integral division

Division operations on integral types always truncate remainders. Dividing by a variable whose value is 0 generates a runtime error (a DivisionByZeroException). Dividing by the literal 0 generates a compile-time error.

Integral overflow

At runtime, arithmetic operations on integral types can overflow. By default, this happens silently—no exception is thrown. While the C# specification is agnostic as to the result of an overflow, the CLR always causes wraparound behavior. For example, decrementing the minimum possible int value results in the maximum possible int value:

	int a = int.MinValue;
	a--;
	Console.WriteLine (a == int.MaxValue); // True

Integral arithmetic overflow check operators

The checked operator tells the runtime to generate an OverflowException rather than failing silently when an integral expression or statement exceeds the arithmetic limits of that type. The checked operator affects expressions with the ++, --, (unary) -, +, -, *, /, and explicit conversion operators between integral types.

checked can be used around either an expression or a statement block. For example:

	int a = 1000000, b = 1000000;

	int c = checked (a*b);     // Checks just the expression

	checked                   // Checks all expressions
	{                         // in statement block
	  c = a * b;
	  ...
	}

You can make arithmetic overflow checking the default for all expressions in a program by compiling with the /checked+ command-line switch (in Visual Studio, go to Advanced Build Settings). If you then need to disable overflow checking just for specific expressions or statements, you can do so with the unchecked operator.

Overflow checking for constant expressions

Regardless of the /checked compiler switch, expressions evaluated at compile time are always overflow-checked—unless you apply the unchecked operator:

	int x = int.MaxValue + 1;         // Compile-time error
	int y = unchecked (int.MaxValue + 1);      // No errors

Bitwise operators

C# supports these standard C-style bitwise operations.

Operator

Meaning

Sample expression

Result

~

Complement

~0xfU

0xfffffff0U

&

And

0xf0 & 0x33

0x30

|

Or

0xf0 | 0x33

0xf3

^

Exclusive Or

0xff00 ^ 0x0ff0

0xf0f0

<<

Shift left

0x20 << 2

0x80

>>

Shift right

0x20 >> 1

0x10

8-and 16-Bit Integrals

The 8-and 16-bit integral types are byte, sbyte, short, and ushort. These types lack their own arithmetic operators, so C# implicitly converts them to larger types as required. This can cause a compile-time error when trying to assign the result back to a small integral type:

	short x = 1, y = 1;
	short z = x + y;       // Compile-time error

In this case, x and y are implicitly converted to int so that the addition can be performed. This means the result is also an int, which cannot be implicitly cast back to a short (because it could cause loss of data). To make this compile, we must add an explicit cast:

	short z = (short) (x + y);   // OK

Special Float and Double Values

Unlike integral types, floating-point types have values that certain operations treat specially. These special values are NaN (Not a Number), +∞,-∞ and –0. The float and double classes have constants for NaN,+∞, and -∞, as well as other values (MaxValue, MinValue, and Epsilon). For example:

	Console.Write (double.Negative Infinity);  // -Infinity

The constants that represent special values for double and float are as follows.

Special value

Double constant

Float constant

NaN

double.NaN

float.NaN

+∞

double.PositiveInfinity

float.PositiveInfinity

-∞

double.NegativeInfinity

float.NegativeInfinity

–0

-0.0

-0.0f

Dividing a nonzero number by zero results in an infinite value. For example:

	Console.WriteLine ( 1.0 / 0.0) ;   //  Infinity
	Console.WriteLine (-1.0 / 0.0) ;   // -Infinity
	Console.WriteLine ( 1.0 / -0.0);   // -Infinity
	Console.WriteLine (-1.0 / -0.0);   //  Infinity

Dividing zero by zero, or subtracting infinity from infinity, results in a NaN. For example:

	Console.WriteLine ( 0.0 / 0.0);                // NaN
	Console.WriteLine ((1.0 / 0.0) - (1.0 / 0.0)); // NaN

When using = =, a NaN value is never equal to another value, even another NaN value:

	Console.WriteLine (0.0 / 0.0 == double.NaN);   // False

To test whether a value is NaN, you must use the float.IsNaN or double.IsNaN method, as follows:

	Console.WriteLine (double.IsNaN (0.0 / 0.0));   // True

Note

float and double follow the specification of the IEEE 754 format types, supported natively by almost all processors. You can find detailed information on the behavior of these types at http://www.ieee.org.

When using object.Equals, however, two NaN values are equal:

	Console.WriteLine
	  (object.Equals (0.0 / 0.0, double.NaN));    // True

double Versus decimal

double is useful for scientific computations (such as computing spatial coordinates); decimal is useful for financial computations.

Category

double

decimal

Internal representation

Base 2

Base 10

Precision

15-16 significant figures

28-29 significant figures

Range

±(~10–324 to ~10308)

±(~10–28 to ~1028)

Special values

+0, –0, +∞, -∞, and NaN

None

Speed

Native to processor

Nonnative to processor (about 10 times slower than double)

Real Number Rounding Errors

float and double internally represent numbers in base 2. For this reason, only numbers expressible in base 2 are represented precisely. Practically, this means most literals with a fractional component (which are in base 10) will not be represented precisely. For example:

	float tenth = 0.1f;                     // Not quite 0.1
	float one   = 1f;
	Console.WriteLine (one - tenth * 10f);  // -1.490116E-08

This is why float and double are bad for financial calculations. In contrast, decimal works in base 10 and so can precisely represent numbers expressible in base 10 (as well as its factors, base 2 and base 5). Because real literals are in base 10, decimal can precisely represent numbers such as 0.1. However, neither double nor decimal can precisely represent a fractional number whose base–10 representation is recurring:

	decimal m = 1M / 6M; // 0.1666666666666666666666666667M
	double d = 1.0 / 6.0;            // 0.16666666666666666

This leads to accumulated rounding errors:

	decimal notQuiteWholeM =
	   m+m+m+m+m+m;       // 1.0000000000000000000000000002M
	double notQuiteWholeD =
	   d+d+d+d+d+d;       // 0.99999999999999989

which breaks equality and comparison operations:

	Console.WriteLine (notQuiteWholeM == 1M); // False
	Console.WriteLine (notQuiteWholeD < 1.0); // True


[1] Technically, decimal is a floating-point type too, although it’s not referred to as such in the C# language specification.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset