Chapter 1. Numbers

Simple types are value types that are a subset of the built-in types in Visual C# .NET, although, in fact, the types are defined as part of the .NET Framework Class Library (.NET FCL). Simple types are made up of several numeric types and a bool type. These numeric types consist of a decimal type (decimal), nine integral types (byte, char, int, long, sbyte, short, uint, ulong, ushort), and two floating-point types (float, double). Table 1-1 lists the simple types and their fully qualified names in the .NET Framework.

Table 1-1. The simple data types

Fully qualified name

Reserved C# keyword

Value range

System.Boolean

bool

true or false

System.Byte

byte

0 to 255

System.SByte

sbyte

-128 to 127

System.Char

char

0 to 65535

System.Decimal

decimal

-79,228,162,514,264,337,593,543,950,335 to 79,228,162,514,264,337,593,543,950,335

System.Double

double

-1.79769313486232e308 to 1.79769313486232e308

System.Single

float

-3.402823e38 to 3.402823e38

System.Int16

short

-32768 to 32767

System.Uint16

ushort

0 to 65535

System.Int32

int

-2,147,483,648 to 2,147,483,647

System.UInt32

uint

0 to 4,294,967,295

System.Int64

long

-9,223,372,036,854,775,808 to 9,223,372,036,854,775,807

System.UInt64

ulong

0 to 18,446,744,073,709,551,615

The C# reserved words for the various data types are simply aliases for the fully qualified type name. Therefore, it does not matter whether you use the type name or the reserved word: the C# compiler will generate identical code.

It should be noted that the following types are not CLS-compliant: sbyte, ushort, uint, and ulong. These types do not conform to the rules governing CLS types and therefore, they might not be supported by other .NET languages. This lack of support might limit or impede the interaction between your C# code and code written in another CLS-compliant language, such as Visual Basic .NET.

1.1. Determining Approximate Equality Between a Fraction and Floating-Point Value

Problem

You need to compare a fraction with a value of type double or float to determine whether they are within a close approximation to each other. Take, for example, the result of comparing the expression 1/6 and the value 0.16666667. These seem to be equivalent, except that 0.16666666 is precise to only 8 places to the right of the decimal point, and 1/6 is precise to the maximum number of digits to the right of the decimal point that the data type will hold.

Solution

Verify that the difference between the two values is within an acceptable tolerance:

using System;

public static bool IsApproximatelyEqualTo(double numerator, 
                                          double denominator, 
                                          double dblValue,
                                          double epsilon)
{
    double difference = (numerator/denominator) - dblValue;

    if (Math.Abs(difference) < epsilon)
    {
        // This is a good approximation
        return (true);
    }
    else
    {
        // This is NOT a good approximation
        return (false);
    }
}

Replacing the type double with float allows you to determine whether a fraction and a float value are approximately equal.

Discussion

Fractions can be expressed as a numerator over a denominator; however, storing them as a floating-point value might be necessary. Storing fractions as floating-point values introduces rounding errors that make it difficult to perform comparisons. Expressing the value as a fraction (e.g., 1/6) allows the maximum precision. Expressing the value as a floating-point value (e.g., 0.16667) can limit the precision of the value. In this case, the precision depends on the number of digits that the developer decides to use to the right of the decimal point.

You might need a way to determine whether two values are approximately equal to each other. This comparison is achieved by defining a value (epsilon) that is the smallest positive value, greater than zero, in which the absolute value of the difference between two values (numerator/denominator - dblValue) must be less than. In other words, by taking the absolute value of the difference between the fraction and the floating-point value and comparing it to a predetermined value passed to the epsilon argument, we can determine whether the floating-point value is a good approximation of the fraction.

Consider a comparison between the fraction 1/7 and its floating-point value, 0.14285714285714285. The following call to the IsApproximatelyEqualTo method indicates that there are not enough digits to the right of the decimal point in the floating-point value to be a good approximation of the fraction (there are 6 digits, although 7 are required):

bool Approximate = Class1.IsApproximatelyEqualTo(1, 7, .142857, .0000001);
// Approximate == false

Adding another digit of precision to the third parameter of this method now indicates that this more precise number is what we require for a good approximation of the fraction 1/7:

bool Approximate = Class1.IsApproximatelyEqualTo(1, 7, .1428571, .0000001);
// Approximate == true

See Also

See the “Double.Epsilon Field” and “Single.Epsilon Field” topics in the MSDN documentation.

Get C# Cookbook now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.