The BugCatcher Chronicles #2 - Pine Hills

Elena

The flickering streetlamp fought valiantly, but in the end Elena was victorious once again.

The green mantis/cricket hybrid that had been resisting her invocations finally gave up the ghost, melting into the virtual ground before materializing as a tiny pixelated icon in the upper-right corner of her phone's screen. The evening had been good to them so far; this was the third such avatar they'd captured. The path of broken streetlamps they'd carved through the neighborhood was a testament to their success.

"Nice inputs, babe." said a voice, hovering over her left shoulder.

"Thanks, Greg. How's yours going?"

"Not too bad." A quick glance at his screen showed a pink rhinoceros beetle clacking its jaws at him. He spun the input selectors again, tapped the invoke button, and the beetle lost one of its jaws. Startled, it attempted to flee, but a quick invocation finally brought it down. The beetle evaporated and rematerialized, and the garage door at the house across the street started to rise of its own accord.

"Shit. Better move!"

Elena quickly followed Greg's fleeing footsteps, and the two scrambled over the next hill, pausing to catch their breath under one of the pine trees that the neighborhood was famous for. They'd gotten away, like they always did. The setting sun framed the outline of the cookie-cutter houses, melting them into an endless skyline of sameness. Elena wondered how any of the residents could find their own home amongst all these identical facades.

"Woo! Got 'em!" cheered Greg. "We're killing it tonight babe!"

"Yeah we are!" affirmed Elena, pulling her hood back up over her head. It was chilly tonight, and while she didn't feel like going home yet, the cold was started to seep through her jacket.

"Any more nearby?" she asked. "I don't see them."

"There may be another over that hill to the west." said Greg. "I mean, we had good luck there yesterday."

"Cool, let's go."

The two slid their phones back into their pockets, volume turned all the way up so as to hear the rhythmic beeps that signify a nearby bug. These bugs are what Elena and Greg are after; software bugs that exist in the real world that, somehow, this app BugCatcher can find and invoke. Once invoked, Elena and Greg get a new, custom-generated avatar for their collection.

Of course, whatever the bug actually does will also happen, hence the trail of broken streetlights and the now-stuck-open garage door.

Elena slid her left hand into Greg's right. He'd been the one to introduce her to the game and, frankly, it had been a lot of fun. Find a bug, try some inputs, capture the bug, see what it did. Everything they'd captured so far had involved broken streetlamps or sprinkler systems gone haywire or suddenly-loud music systems; in other words, nothing too serious. The worst thing that had happened was that they'd accidentally turned a car on, with no way to turn it off. It hadn't been shifted out of park, so Elena figured it was no big deal; it couldn't go anywhere.

As they crested the hill, Elena got a glimpse of the rest of the neighborhood. It was quite nice, to be sure, but it was also so... dull. Every house was the same, with a big green yard, 2.5 children and a dog. Bland, unoriginal, inoffensive, boring.

It didn't really bother her that they were out here catching bugs, breaking streetlamps and sprinkler systems. After all, if anybody could afford the mild chaos she and Greg were causing, it was these people. Goddamn rich people.

A low drone sounded from Greg's pocket, and Elena's started doing the same. A bug was nearby. As if by magic, Greg's phone appeared in his hand as though it had been there all along. Elena was a bit slower, but in a couple seconds they had located the bug. Apprehension turned to amazement as they beheld the monstrosity before them.

It had the body of a caterpillar, but the clacking mandibles of a fire ant. The thing writhed in an unnatural way, as if trying to shake some invisible bond that held it within the phone. It was huge, almost as big as the house nearby, with giant black eyes that seemingly reflected the virtual light which attempted to pass through them. Elena was amazed at the design quality of this particular avatar; whoever coded this up did a hell of a job.

Greg was quicker, as always, and his first few invocations started flying. Elena joined in on her app, working the opposite way Greg was, just like he'd taught her. Between the two of them, they'd always managed to find the right combination of inputs to invoke the bug and capture the monster before it had a chance to flee.

This one proved difficult. Several rounds went by, and nothing was taking. The caterpillar's writhing continued, and it looked to Elena like it was specifically programmed to come leaping out of her phone if she failed to catch it.

Finally something stuck. The leftmost input glowed with a red outline, and the monster's right side started limping. She'd found something!

"Red 47!" she whispered urgently to Greg. "That's the left input!"

A moment later, he whispered back: "Black 12 is the middle."

All they needed now was the right side. Her fingers flew across the screen as she desperately tried combination after combination, willing the app to give her the right answer so she might have this bug for her collection.

Sustaining hit after hit, the caterpillar monster finally collapsed, dead, and faded away. The pixelated avatar appeared, and despite herself she let out a whoop of joy.

"Nice job, babe," said Greg, though not without a hint of jealousy.

"Hey, it was you who figured out the middle input."

"Yeah, but you brought it down. Make sure to show that to Danny when we get back to campus."

The two started back the way they came. Only a moment later, the trees became illuminated in red and blue, and a police cruiser slammed to a stop right next to the pair of hunters. Another cruiser followed on the heels of the first one, and three offices exited the two vehicles.

"Hands up!" shouted the nearest officer. "Don't move."

Greg glanced at Elena, and she could tell what he was thinking. Should we move? She shook her head, almost imperceptibly, and raised her hands. No point. He reluctantly did the same.

The nearest officer took Greg over toward the nearby tree, cuffed him, and slid him into the back of the first cruiser. Another officer cuffed Elena, and as she was being walked to the second cruiser she belatedly realized that the officer that had cuffed her had also been speaking to her, though she couldn't remember what he had been saying.

I'm being arrested! For what?!

As she took a seat in the back of the cruiser, she wondered how the hell it had come to this. Goddamn rich people, thinking they own the world. It was just some broken streetlamps. We didn't do anything!

Frank

Twenty minutes before the police showed up way earlier than she'd expected them to, Georgia Huntsworth sat in an easy chair and stared blankly at the TV. The family insisted that having it on helped poor Frank, but Georgia just couldn't see how. The man was a vegetable, with no hope of waking up anytime soon. He'd have no idea it was even on, much less be able to watch it.

She sighed, and got up to fix another cup of coffee. A stronger one, this time. The gentle whirring of Frank's artificial breathing machine faded into the background as Georgia crossed into the house's kitchen. It would be a long night, but the machines would do most of the work. All she had to do was make sure he was comfortable; at least, as comfortable as she could imagine him being.

She placed the pot back on its mantle and leaned against the countertop. The job wasn't bad, per se, it was just boring. There really wasn't much to do for poor old Frank. She made him comfortable, she kept the TV on, and otherwise she chatted with her coworkers or her daughter or her beloved Zachary. It was a good job, just not very exciting.

The coffee was done, so Georgia poured herself a mug and went back to the easy chair. She glanced at Frank; nothing had changed, and she mentally chastised herself for thinking that something might. She sat down, dug out her phone, and starting to type a message for Zachary.

Then she realized that Frank was no longer breathing.

And, even worse, there was no whirring noise.

She checked the machine. It was off, and silent, though she'd been told that if it failed it's alarm would go off. She checked for Frank's pulse, found it, weak but present, and scrambled to dial 911. Once that call was finished, she straddled Frank's still body and began performing CPR on him, hoping to keep his blood pumping long enough to get him to the hospital.

Thirty seconds later, the red-and-blue flashes of the police cruisers arrived, and Georgia was impressed with their promptness, only to be disappointed when they left prematurely. They were followed a minute later by an ambulance. An EMT burst through the open front door, relieved Georgia, and together they loaded Frank into the ambulance.

Elena

The room was bright, unnaturally so, and Elena's eyes were having a hard time adjusting. When the burly detective (Elena assumed he was a detective, given that he didn't wear a uniform) slammed the door open and barged into the tiny room, she nearly jumped out of her chair.

"Well now, little missy, mind telling me what you were doing out in Pine Hills tonight?"

"I, uh, I was just playing a game," she stammered. "We both were."

"That's a hell of game, then." The detective's voiced boomed off the walls; Elena thought she saw the one-way mirror rattle. "Four broken street lamps, one garage door stuck open, two sprinkles systems that now need extensive repairs. You know the whole neighborhood saw you two, right?"

Elena hadn't known that, but it seemed blindingly obvious now, so out of fear of embarrassing herself she kept her mouth shut.

The detective wasn't fooled. "Right. So would it surprise you to learn that all that property damage wasn't all you did?"

"What? I swear, all we were doing was catching bugs!" Elena insisted.

"I'm sure. I doubt the family of Frank Doornbos will be so understanding."

What the hell is he talking about? Elena wondered. I don't know any Frank Doornbos. Probably some damn rich guy who lives in that neighborhood.

When she realized what the detective had actually said, Elena felt a chill run down her spine.

"What does that mean?"

"We've already arrested you for destruction of property. Our officers picked you up outside of Mr. Doornbos's home. We know you were playing BugCatcher, despite that game being illegal in this state. You really want to add obstruction of justice to your rap sheet?"

"I swear, I don't know what you are talking about." Elena couldn't believe what she was hearing. BugCatcher was illegal? Why hadn't Greg mentioned that?

"Oh, all right then. I'll spell it out for you. Frank Doornbos is dead. Whatever you two and that app did, it caused his artificial breathing machine to stop working. His nurse called 911, performed CPR, the works, but it was too late. He was dead before they reached the hospital."

Elena's arms and legs went numb. That bug, the last one they'd caught before the police picked them up, the huge jawed caterpillar thing. It had killed someone?

Her face must have given her away, because she looked up from the metal table in front of her to see the detective's eyes boring holes into her skull. Her mind furiously searched for something, anything, to say.

"No, see, you got it all wrong," Elena fought through tears that threatened to overwhelm her. This was all wrong, it was just some fun at the expense of rich people, they weren't doing any real harm. "We were just catching bugs, we didn't kill anyone."

"Oh, but see, you did." The detective smiled, if you could call a mouth full of teeth a smile. "You invoked that bug. That bug shut off the breathing machine, which killed Frank Doornbos. Therefore, you killed Frank Doornbos." He slammed a file down on the desk and Elena jumped. "We are charging you with second-degree murder. Your boyfriend has already confessed; you would be wise to do the same. We will notify your family, and it would be wise to get a lawyer."

The detective picked up the file and walked out of the brightly-lit room, the door slamming behind him. From within the room, sniffles turned to sobs, and the detective strode down the long hallway to his desk.

As he approached, he heard a low drone sounding from his desk drawer, and he grinned.

A Simple Caching Scheme for Web API using Dependency Injection

I use Dependency Injection (DI) quite a bit in my ASP.NET projects, particularly in Web API and MVC web applications. Recently, I had a need to implement a caching layer in one of my MVC apps, and such a layer would be best used if it could be injected into my clients layer (e.g. the layer that called an API and handled responses from the same). The solution I came up with seemed to be pretty simple, so I wanted to share it here.

In this post, we're going to set up a simple MVC project that consumes a Web API and implements a caching layer.

Requirements

For this project, I'm using two of my favorite NuGet packages:

The sample project, which is over on GitHub, is a fully-functional implementation of the strategy described in this post. Feel free to check it out, branch it, download it, whatever!

Setting Up the API

First, let's take a look at our sample API. Here's the class DateNumberObject, which represents a response returned from the API to the web project:

public class DateNumberObject  
{
    public DateTime CurrentDate { get; set; }
    public int RandomNumber { get; set; }

    public DateNumberObject()
    {
        CurrentDate = DateTime.Now;
        Random rand = new Random();
        RandomNumber = rand.Next(1, 200);
    }
}

As you can see, all this class does is return the current date and time and a random number.

We can now build our API, which is also rather simple. Here's a snippet from the API's controller:

[RoutePrefix("samples")]
public class SampleController : ApiController  
{

    [HttpGet]
    [Route("date")]
    public IHttpActionResult GetDateAndNumber()
    {
        return Ok(new DateNumberObject());
    }
}

That's all our API will do: return the current date and a random number. Since there's no caching taking place at the service layer, we will need to implement caching at the web layer.

Speaking of the web layer, in our sample solution it is an MVC5 project, and we will be using my favorite Dependency Injection tool, StructureMap.

Setting up StructureMap

If you've never set up StructureMap in your MVC projects, you'll want to read this section; otherwise, skip to the next section.

The first thing we need to do is download the StructureMap.MVC5 NuGet package, which will add a DependencyInjection folder and a StructuremapMvc file to our app:

Inside the Dependency Resolution folder will be a file called DefaultRegistry.cs, which will initially look something like this:

namespace WebApiCacheDemo.Mvc.DependencyResolution {  
    using Caching;
    using StructureMap.Configuration.DSL;
    using StructureMap.Graph;

    public class DefaultRegistry : Registry {
        #region Constructors and Destructors
        public DefaultRegistry() {
            Scan(
                scan => {
                    scan.TheCallingAssembly();
                    scan.WithDefaultConventions();
                    scan.With(new ControllerConvention());
                });
        }
        #endregion
    }
}

The way StructureMap works is that it keeps instances of classes that need to be "injected" into other classes in a Container class, and uses these instances any time a particular interface is called for in another class. You'll see exactly what this means in the next section.

The Uncached Example

Let's build the uncached example first, and we can begin by setting up the MVC client. For this project we'll be using RestSharp (which I have also written about before) to consume the API responses, so be sure to download the NuGet package.

Because we're using Dependency Injection, we need our clients to be injectable into our controllers. For this reason, we will make both an interface and a class for our client, like so:

public interface ISampleClient : IRestClient  
{
    DateNumberObject GetSampleDateAndNumberUncached();
}

public class SampleClient : RestClient, ISampleClient  
{
    public SampleClient()
    {
        BaseUrl = new Uri("http://localhost:58566/");
    }

    public DateNumberObject GetSampleDateAndNumberUncached()
    {
        RestRequest request = new RestRequest("samples/date", Method.GET);
        var response = Execute<DateNumberObject>(request);
        return response.Data;
    }
}

Note that we don't need to register this client with StructureMap because the naming follows the standard conventions (ISampleClient maps to SampleClient).

Now we need our controller...

[RoutePrefix("Home")]
public class HomeController : Controller  
{
    private ISampleClient _sampleClient;

    public HomeController(ISampleClient sampleClient)
    {
        _sampleClient = sampleClient;
    }

    [HttpGet]
    [Route("Uncached")]
    [Route("")]
    [Route("~/")]
    public ActionResult Uncached()
    {
        var model = _sampleClient.GetSampleDateAndNumberUncached();
        return View(model);
    }
}

...which returns a view:

@model WebApiCacheDemo.Contracts.Samples.DateNumberObject
@{
    ViewBag.Title = "Uncached Date Sample";
}

<h2>Uncached Results</h2>  
<div class="row">  
    <span><strong>Current Date:</strong></span>
    @Model.CurrentDate
</div>  
<div class="row">  
    <span><strong>Random Number:</strong></span>
    @Model.RandomNumber
</div>  

When we run this, we can see that the view returns the newest date and time, as shown in this gif:

That's exactly what we would expect to see, of course. Now, we can get down to implementing a cache at the web layer for this.

The Cached Example

The first thing we need is our CacheService interface and implementation, which I totally stole from this StackOverflow answer:

public class InMemoryCache : ICacheService  
{
    public T GetOrSet<T>(string cacheKey, Func<T> getItemCallback) where T : class
    {
        T item = MemoryCache.Default.Get(cacheKey) as T;
        if (item == null)
        {
            item = getItemCallback();
            MemoryCache.Default.Add(cacheKey, item, DateTime.Now.AddMinutes(30));
        }
        return item;
    }
}

public interface ICacheService  
{
    T GetOrSet<T>(string cacheKey, Func<T> getItemCallback) where T : class;
}

We also need our SampleClient class updated to use this cache service, like so:

public class SampleClient : RestClient, ISampleClient  
{
    private ICacheService _cache;
    public SampleClient(ICacheService cache)
    {
        _cache = cache;
        BaseUrl = new Uri("http://localhost:58566/");
    }

    public DateNumberObject GetSampleDateAndNumber()
    {
        return _cache.GetOrSet("SampleDateAndNumber", () => GetSampleDateAndNumberUncached());
    }

    public DateNumberObject GetSampleDateAndNumberUncached()
    {
        RestRequest request = new RestRequest("samples/date", Method.GET);
        var response = Execute<DateNumberObject>(request);
        return response.Data;
    }
}

NOTE: In my structure, I am intentionally implementing the cached and uncached operations as separate methods in the same client, so that either one can be used. This may or may not be the correct usage in your application.

Further, we need to update our controller:

[RoutePrefix("Home")]
public class HomeController : Controller  
{
    ...

    [HttpGet]
    [Route("Cached")]
    public ActionResult Cached()
    {
        var model = _sampleClient.GetSampleDateAndNumber();
        return View(model);
    }
}

The last step is to register the ICacheService implementing in StructureMap's DefaultRegistry.cs class:

namespace WebApiCacheDemo.Mvc.DependencyResolution {  
    ...

    public class DefaultRegistry : Registry {
        public DefaultRegistry() {
            ...
            var inMemoryCache = new InMemoryCache();
            For<ICacheService>().Use(inMemoryCache);
        }
    }
}

Now, when we run this sample, we will see the cached values for the date and number, as shown in the following gif:

Now we've successfully implemented our cache AND used Dependency Injection in the process!

Summary

With this structure, we've successfully implemented a caching layer into our MVC application, all while using StructureMap to provide Dependency Injection. This structure allows us to potentially swap cache providers (in case we, say, move to a database-located cache for server farms) without too much trouble, as well as injecting the cache service into our existing clients.

Don't forget to check out the sample project over on GitHub, and feel free to point out how you've used this implemention or where it can be improved in the comments.

Happy Coding!

Show Up, Kick Ass, Go Home

I refuse to work overtime. In the five years I've been at my current company, I've worked overtime exactly once, and that was because our server was literally on fire. Overtime is just not worth it to me.

I'm a salaried employee. A rather well-paid salaried employee, at least compared to many other professions. In the United States where I live (where I am classified as an "exempt" employee), that means that I will not be paid for work done above and beyond 40 hours a week. So, as far as I am concerned, my employer pays me to work 40 hours a week. I show up on time, I kick ass for 8 hours a day, and then I go home.

What I don't do, at least not on a regular basis, is work overtime.

Unpaid overtime dilutes your hourly rate. If you get paid a salary of $60k per year, that's approximately $29/hr if you work 40 hours a week. If you work just 5 hours more a week (45 hours per week), your hourly rate diminishes to approximately $26/hr. You've just devalued yourself by $3 an hour. Further, you've told your company that that's what your worth, since they're already paying you a set amount. From their perspective, overtime is free work, and who would turn down free work?

And for what? I'm an American, but one of the apparent ideals this country seems to hold is absolutely ludicrous to me: I don't live to work. I've written before that I live to live, to do things with my family. I don't want more money; I already have enough that my family and I can live comfortably, if not extravagantly. I want more time.

Time is the one thing I can't ever get more of. No amount of salary negotiations, of GitHub commits, of stand up meetings can ever replace the time with my family that I lose when I work. And "lose" is the correct word here; it's not time I can make back up.

I have to wonder: why do so many people do this? Why do so many people commit themselves body and soul to a company, to work? I don't have any proof, but I personally think it has a lot to do with the illusion of control.

See, in many people's lives, things are simply beyond our control. We can't always protect our children from every little thing; we can't always get that promotion we so desire; hell, we can't even always catch the damn Pokemon that we need to complete our collection. But we can do our job. We can file the correct paperwork, we can write the appropriate tests, we can get all the appropriate projects planned out months in advance. Those are things we can control.

Control is a big deal. Anything we can control, we tend to hold on to for far longer than we should, far longer than is rational (not that humans are always rational, of course). After all, why lose something when all it takes is our hard work to make it worthwhile?

But it's not. Hard work, work above and beyond what you get paid to do, is not worthwhile. It's the opposite of worthwhile, because it diminishes the amount of time you get to spend on other activities. It reduces the time spent with your family, with your loved ones, with your hobbies that give you purpose. It gives us control, but it also wastes our time. It's a time-sink.

Now, at this point in my life, my most valuable commodity is not money, it's time. I can't get any more, no matter how hard I work. I have a limited amount of keystrokes left in my life and I refuse to voluntarily use them up for some company, some effort, some goal that I don't believe in. I've done that before, and it never works out.

Fellow salaried employees: don't work overtime, at least not on a regular basis. Your time is more valuable than that.

Decimal vs Double and Other Tips About Number Types in .NET

I've been coding with .NET for a long time. In all of that time, I haven't really had a need to figure out the nitty-gritty differences between float and double, or between decimal and pretty much any other type. I've just used them as I see fit, and hope that's how they were meant to be used.

Until recently, anyway. Recently, as I was attending the AngleBrackets conference, and one of the coolest parts of attending that conference is getting to be in an in-depth workshop. My particular workshop was called I Will Make You A Better C# Programmer by Kathleen Dollard, and my reaction was thus:

One of the most interesting things I learned at Kathleen's session was that the .NET number types don't always behave the way I think they do. In this post, I'm going to walk through a few (a VERY few) of Kathleen's examples and try to explain why .NET has so many different number types and what they are each for. Come along as I (with her code) attempt to show what the number types are, and what they are used for!

The Number Types in .NET

Let's start with a review of the more common number types in .NET. Here's a few of the basic types:

  • Int16 (aka short): A signed integer with 16 bits (2 bytes) of space available.
  • Int32 (aka int): A signed integer with 32 bits (4 bytes) of space available.
  • Int64 (aka long): A signed integer with 64 bits (8 bytes) of space available.
  • Single (aka float): A 32-bit floating point number.
  • Double (aka double): A 64-bit floating-point number.
  • Decimal (aka decimal): A 128-bit floating-point number with a higher precision and a smaller range than Single or Double.

There's an interesting thing to point out when comparing double and decimal: the range of double is ±5.0 × 10−324 to ±1.7 × 10308, while the range of decimal is (-7.9 x 1028 to 7.9 x 1028) / (100 to 28). In other words, the range of double is several times larger than the range of decimal. The reason for this is that they are used for quite different things.

Precision vs Accuracy

One of the concepts that's really important to discuss when dealing with .NET number types is that of precision vs. accuracy. To make matters more complicated, there are actually two different definitions of precision, one of which I will call arithmetic precision.

  • Precision refers to the closeness of two or more measurements to each other. If you measure something five times and get exactly 4.321 each time, your measurement can be said to be very precise.
  • Accuracy refers to the closeness of a value to standard or known value. If you measure something, and find it's weight to be 4.7kg, but the known value for that object is 10kg, your measurement is not very accurate.
  • Arithmetic precision refers to the number of digits used to represent a number (e.g. how many numbers after the decimal are used). The number 9.87 is less arithmetically precise than the number 9.87654332.

We always need mathematical operations in a computer system to be accurate; we cannot ever expect 4 x 6 = 32. Further, we also need these calculations to be precise using the common term; 4 x 6 must always be precisely 24 no matter how many times we make that calculation. However, the extent to which we want our systems to be either arithmetically precise has a direct impact on the performance of those system.

If we lose some arithmetic precision, we gain performance. The reverse is also true: if we need values to be arithmetically precise, we will spend more time calculating those values. Forgetting this can lead to incredible performance problems, problems which can be solved by using the correct type for the correct problem. These kinds of issues are most clearly shown during Test 3 later in this post.

Why Is Int The Default?

Here's something I've always wondered. If you take this line of code:

var number = 5;  

Why is the type of number always an int? Why not a short, since that takes up less space? Or maybe a long, since that will represent nearly any integer we could possibly use?

Turns out, the answer is, as it often is, performance. .NET optimizes your code to run in a 32-bit architecture, which means that any operations involving 32-bit integers will by definition be more performant than either 16-bit or 64-bit operations. I expect that this will change as we move toward a 64-bit architecture being standard, but for now, 32-bit integers are the most performant option.

Testing the Number Types

One of the ways we can start to see the inherent differences between the above types is by trying to use them in calculations. We're going to see three different tests, each of which will reveal a little more about how .NET uses each of these types.

Test 1: Division

Let's start with a basic example using division. Consider the following code:

private void DivisionTest1()  
{
    int maxDiscountPercent = 30;
    int markupPercent = 20;
    Single niceFactor = 30;
    double discount = maxDiscountPercent * (markupPercent / niceFactor);
    Console.WriteLine("Discount (double): ${0:R}", discount);
}

private void DivisionTest2()  
{
    byte maxDiscountPercent = 30;
    int markupPercent = 20;
    int niceFactor = 30;
    int discount = maxDiscountPercent * (markupPercent / niceFactor);
    Console.WriteLine("Discount (int): ${0}", discount);
}

Note that the only thing that's really different about these two methods are the types of the local variables.

Now here's the question: what will the discount be in each of these methods?

If you said that they'll both be $20, you're missing something very important.

The problem line is this one, from DivisionTest2():

int discount = maxDiscountPercent * (markupPercent / niceFactor);  

Here's the problem: because markupPercent is declared as an int (which in turn makes it an Int32), when you divide an int by another int, the result will be an int, even when we would logically expect it to be something like a double. .NET does this by truncating the result, so because 20 / 30 = 0.6666667, what you get back is 0 (and anything times 0 is 0).

In short, the discount for DivisionTest1 is the expected $20, but the discount for DivisionTest2 is $0, and the only difference between them is what types are used. That's quite a difference, no?

Test 2 - Double Addition

Now we get to see something really weird, and it involves the concept of arithmetic precision from earlier. Here's the next method:

public void DoubleAddition()  
{
    Double x = .1;
    Double result = 10 * x;
    Double result2 = x + x + x + x + x + x + x + x + x + x;

    Console.WriteLine("{0} - {1}", result, result2);
    Console.WriteLine("{0:R} - {1:R}", result, result2);
}

Just by reading this code, we expect result and result2 to be the same: multiplying .1 x 10 should equal .1 + .1 + .1 + .1 + .1 + .1 + .1 + .1 + .1 + .1.

But there's another trick here, and that's the usage of the "{O:R}" string formatter. That's called the round-trip formatter, and it tells .NET to display all parts of this number to its maximum arithmetic precision.

If we run this method, what does the output look like?

By using the round-trip formatter, we see that the multiplication result ended up being exactly 1, but the addition result was off from 1 by a miniscule (but still potentially significant) amount. Question is: why does it do this?

In most systems, a number like 0.1 cannot be accurately represented using binary. There will be some form of arithmetic precision error when using a number such as this. Generally, said arithmetic precision error is not noticeable when doing mathematical operations, but the more operations you perform, the more noticeable the error is. The reason we see the error above is because for the multiplication portion, we only performed one operation, but for the addition portion, we performed ten, and thus caused the arithmetic precision error to compound each time.

Test 3 - Decimal vs Double Performance

Now we get to see something really interesting. I'm often approached by new .NET programmers with a question like the following: why should we use decimal over double and vice-versa? This test pretty clearly spells out when and why you should use these two types.

Here's the sample code:

private int iterations = 100000000;

private void DoubleTest()  
{
    Stopwatch watch = new Stopwatch();
    watch.Start();
    Double z = 0;
    for (int i = 0; i < iterations; i++)
    {
        Double x = i;
        Double y = x * i;
        z += y;
    }
    watch.Stop();
    Console.WriteLine("Double: " + watch.ElapsedTicks);
    Console.WriteLine(z);
}

private void DecimalTest()  
{
    Stopwatch watch = new Stopwatch();
    watch.Start();
    Decimal z = 0;
    for (int i = 0; i < iterations; i++)
    {
        Decimal x = i;
        Decimal y = x * i;
        z += y;
    }
    watch.Stop();
    Console.WriteLine("Decimal: " + watch.ElapsedTicks);
    Console.WriteLine(z);
}

For each of these types, we are doing a series of operations (100 million of them) and seeing how many ticks it takes for the double operation to execute vs how many ticks it takes for the decimal operations to execute. The answer is startling:

The operations involving double take 790836 ticks, while the operations involving decimal take a whopping 16728386 ticks. In other words, the decimal operations take 21 times longer to execute than the double operations. (If you run the sample project, you'll notice that the decimal operations take visibly longer than the double ones).

But why? Why does double take so much less time than decimal?

For one thing, double uses base-2 math, while decimal uses base-10 math. Base-2 math is much quicker for computers to calculate.

Further, what double is concerned with is performance, while what decimal is concerned with is precision. When using double, you are accepting a known trade-off: you won't be super precise in your calculations, but you will get an acceptable answer quickly. Whereas with decimal, precision is built into its type: it's meant to be used for money calculations, and guess how many people would riot if those weren't accurate down to the 23rd place after the decimal point.

In short, double and decimal are two totally separate types for a reason: one is for speed, and the other is for precision. Make sure you use the appropriate one at the appropriate time.

Summary

As can be expected from such a long-lived framework, .NET has several number types to help you with your calculations, ranging from simple integers to complex currency-based values. As always, it's important to use the correct tool for the job:

  • Use double for non-integer math where the most precise answer isn't necessary.
  • Use decimal for non-integer math where precision is needed (e.g. money and currency).
  • Use int by default for any integer-based operations that can use that type, as it will be more performant than short or long.

Don't forget to check out the sample project over on GitHub!

Are there any other pitfalls or improvements we should be aware of? Feel free to sound off in the comments!

Happy Coding!

Huge thanks to Kathleen Dollard (@kathleendollard) for providing the code samples and her invaluable insight into how to effectively explain what's going on in these samples. Check out her Pluralsight course for more!