12,395,871 members (56,800 online)
Tip/Trick
alternative version

3.6K views
4 bookmarked
Posted

# Go to Basic/ .NET Floating Numbers

, 10 Mar 2014 CPOL
 Rate this:
Go to Basic/ .NET Floating Numbers

## Introduction

This tip reveals number problems that exist in .NET. The first part describes common limitations of floating numbers. In the second part specific to .NET number problems are shown.

This will be very helpful for junior and mid level developers, though still in my career I have been meeting senior developers that are not aware of such basic things.

## Part 1 - Floating Numbers

There are 3 types of floating numbers in .NET:

```float or System.Single    // 32 bit floating number with base 2
double  or System.Double  // 64 bit floating number with base 2
decimal or System.Decimal // 128 bit floating number with base 10 ```

(`float`, `double` and `decimal` are the keywords available in C# and not in VB.)

`Decimal` floating number is mostly convenient for people.

``` ```

```decimal m = 102.45m
Dim m As Decimal = 102.45 ```

In the computer, it will be represented approximately as we expected:

```10^2   10^1    10^0 . 10^-1   10^-2
100    10      1    . 1/10     1/100
1      0       2    . 4        5  ```

The same strategy is used in `Single` and `Double` (base 2 floating numbers)

```double d =  12.75
Dim d as Double = 12.75
2^3  2^2   2^1   2^0 . 2^-1  2^-2
8    4     2     1   . 1/2   1/4
----------------------------------------
1    1     0     0   . 1     1          // bit representation
----------------------------------------
8  + 4  +  0  +  0   . 1/2 + 1/4 = 12.75    ```

The first restriction is that sum of 2^(-N) cannot map all fractional numbers with limitation in bits. For example, decimal 0.2 is represented in endless double number.

Using DoubleConverter created by Jon Skeet, we can look at the representation of the number 0.2 in double format:

`0.200000000000000011102230246251565404236316680908203125 `

So do not be surprised in equality checking for base-2 floating numbers (it is always approximation if exact conversion is not possible).

```[TestMethod]
public void DoubleNumberEqualityCheck()
{
double d1 = 0.6 - 0.2;
double d2 = 0.4;
Assert.AreNotEqual(d1, d2); // d1 != d2
}
<TestMethod()> Public Sub DoubleNumberEqualityCheck()
Dim d1 As Double = 0.6 - 0.2
Dim d2 As Double = 0.4
Assert.AreNotEqual(d1, d2)   ' d1 <> d2
End Sub  ```

Use number type that works for the task.
`Decimal` type fits well for money. `Double` and `Single` are good for scientific calculations, because processor works faster with them (than with `Decimal`) and approximation can be smartly taken.

Because of its nature, this limitation exists for any program language (Java, .NET, SQL).

## Part 2 Floating Numbers in .NET

### Not a Number

For `Double` and `Single` type, there are several special values reserved in .NET (and not for `Decimal`).

```Double.NaN;
Double.NegativeInfinity;
Double.PositiveInfinity;

Single.NaN;
Single.NegativeInfinity;
Single.PositiveInfinity;  ```

These numbers can appear in special operations:

• square root from negative number. e.g. `Math.Sqrt(-2)`
• 0 / 0
• 0 * 8
• 8 / 8

Idea behind `NaN` numbers is that it should not be equal to another `NaN` number. Otherwise, how we should compare `Math.Sqrt(-2) `and `Math.Sqrt(-100)`?
So, `Double.Nan != Double.Nan`, however if we compare on equality with `Equals()` method, it will produce very messy result for `NaN` and `Infinity`.

Why `Double.NaN != Double.NaN`, but `Double.NaN.Equals(Double.NaN)` and `Double.PositiveInfinity == Double.PositiveInfinity`?

```[TestMethod]
public void CheckNaNForInequality() // Test will pass without errors
{
double d = Double.NaN;
Assert.IsFalse(d == Double.NaN);
Assert.IsTrue(d.Equals(Double.NaN));
double d2 = Double.PositiveInfinity;
Assert.IsTrue(d2 == Double.PositiveInfinity);
Assert.IsTrue(d2.Equals(Double.PositiveInfinity));
double d3 = Double.NegativeInfinity;
Assert.IsTrue(d3 == Double.NegativeInfinity);
Assert.IsTrue(d3.Equals(Double.NegativeInfinity));
}
<TestMethod()> Public Sub CheckNaNForInequality() // Test will pass without errors
Dim d As Double = Double.NaN
Assert.IsFalse(d = Double.NaN)
Assert.IsTrue(d.Equals(Double.NaN))
Dim d2 As Double = Double.PositiveInfinity
Assert.IsTrue(d2 = Double.PositiveInfinity)
Assert.IsTrue(d2.Equals(Double.PositiveInfinity))
Dim d3 As Double = Double.NegativeInfinity
Assert.IsTrue(d3 = Double.NegativeInfinity)
Assert.IsTrue(d3.Equals(Double.NegativeInfinity))
End Sub   ```

To avoid errors, it is better to use next methods for special number checking:

```Double.IsNaN(value)
Double.IsInfinity(value)

Double.IsNegativeInfinity(value)
Double.IsPositiveInfinity(value) ```

(similar for `Single`)

There is a difference in representation between C# and VB in debug value inspection:

• `NaN` is presented as `NaN` in C# and `-1.#IND` in VB (IND for indeterminate)
• `PositiveInfinity` is presented as `+Infinity` in C# and `1.#INF` in VB
• `NegativeInfinity` is presented as `-Infinity` in C# and `-1.#INF` in VB

## Share

 Software Developer (Senior) Russian Federation
No Biography provided