performance of decimal

Why decimal? If you don’t know when and why you should be using decimal rather then double you are probably, like me, a person with no formal knowledge of computer science and you shouldn’t be allowed to do anything other than a hobby project. But, just for review, here are some nice articles about the subject:

An overview of the different types of number:
http://www.extremeoptimization.com/resources/Articles/FPDotNetConceptsAndFormats.aspx

A full series from Eric Lippert on numbers and particularly floating point numbers:
http://blogs.msdn.com/ericlippert/archive/tags/Floating+Point+Arithmetic/default.aspx

For my purposes the interesting thing is how much faster is double than decimal. The reasons for the speed difference are discussed in some articles but the essential points are the size of the representation of the number is much larger in decimal than it is in double and also there is good hardware support for double calculations. That is, the CPU is better at double than decimal arithmetic. If you don’t see that the representation of numbers makes a difference to how easy arithmetic is then you should try doing long division using roman numerals.

Here is my test code, it is a short and complete program:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DecimalVersusDouble
{
class Program
{
static void Main(string[] args)
{
if (args.Length != 1)
{
throw new ApplicationException(“should only have one argument”);
}

int count = Convert.ToInt32(args[0]);
long start;
long end;

start = DateTime.Now.Ticks;
DoDouble(count);
end = DateTime.Now.Ticks;
Console.WriteLine(“double took :” + TicksToSecondsToString(end, start));

start = DateTime.Now.Ticks;
DoDecimal(count);
end = DateTime.Now.Ticks;
Console.WriteLine(“decimal took:” + TicksToSecondsToString(end, start));
}

private static string TicksToSecondsToString(long end, long start)
{
return (((double)end – (double)start)/10000000.0).ToString();
}

private static decimal[] theDecimals = {1.2m, 2.3m, 4.5m, 6.7m, 8.9m};
private static double[] theDoubles = {1.2, 2.3, 4.5, 6.7, 8.9};

private static void DoDecimal(int totalCount)
{
decimal result = 1;
for(int i = 0; i < totalCount; i++)
{
foreach(decimal number in theDecimals)
{
result = result + number;
}
}
}

private static void DoDouble(int totalCount)
{
double result = 1;
for (int i = 0; i < totalCount; i++)
{
foreach (double number in theDoubles )
{
result = result + number;
}
}
}
}
}

I, with my liking of the command line, use it like this:

  1. save file as decimal.cs
  2. open powershell, and run the script that allows powershell to work like the visual studio command prompt
  3. run csc decimal.cs
  4. run the progam by calling decimal.exe 100000
  5. repeat your measurements by using this powershell one-liner  for($i=0;$i -lt 10; $i++){ .\decimal.exe 10000000 }

results look like this:

PS C:\dev> for($i=0;$i -lt 10; $i++){ .\decimal.exe 10000000  }
double took :0.09376
decimal took:3.5624704
double took :0.0937472
decimal took:3.5624704
double took :0.0937472
decimal took:3.5624832
double took :0.09376
decimal took:3.5624704
double took :0.0937472
decimal took:3.5780992
double took :0.0937472
decimal took:3.5624832
double took :0.109376
decimal took:3.5624832
double took :0.0937472
decimal took:3.6718464
double took :0.109376
decimal took:3.6874752
double took :0.1093632
decimal took:3.6093568

So if you are doing 10,000,000 decimal operations you are burning up seconds.

Of course, if you need to use decimal, you probably need it no matter what. Also bear in mind that the size of decimal will mean that if you are regularly passing these things around a few million times a second, then you will be passing by value and doing a lot of copying. If you are have a set of numbers that you are doing a lot of recalculation on them – say, a portfolio of financial instruments that needs to be revalued every time the prices move – then you can hold them in a collection and pass the collection by reference. Then you won’t be copying them, but you might be opening your class internals in a bad way (see Eric Lippert again: “Arrays considered somewhat harmful” ).

Of course, the converse is true: if you want to do less than 100,000 arithmetic operations per second, then decimal is better and there is no measurable performance cost.

Advertisements

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 )

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s