Fractions!

I haven’t posted much code to my blog lately, so I thought I’d pass along some general-purpose C# code that I recently used in a project. I’m working on a system right now where the original author made some, shall we say, interesting decisions about how to store data in SQL. Specifically, he used varchar fields for most of the numeric data. And, in those fields, he sometimes stores the data in decimal format (e.g. “1.5”), sometimes as fractions (e.g. “1 1/2”) and sometimes as explicitly-signed fractions (“+1 1/2”).  I, of course, need to do LOTS of math on these numbers. The decimal fields can be dealt with using good old TryParse and ToString of course, but there’s no obvious parse routine for fractions, nor is there an obvious way to turn a decimal number back into a fraction string.

The internet, of course, provides. Here is a VB.NET function to turn a fraction string into a decimal and there is some C# code to convert a decimal into a fraction string in this thread. I converted the VB.NET to C#, and cleaned both of them up and put them in a utility class.  Here it is:

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

namespace MySuit.MySuitV2.BLL
{
    public class Utility
    {
        public static decimal FractionToDecimal(string frac)
        {
            // this method should convert a fraction, e.g. "12 1/4" to a decimal, e.g. 12.25.
            // based on http://amrelgarhytech.blogspot.com/2008/03/fraction-to-decimal.html
            // TODO: not sure how best to handle exceptions here. (parse errors, div by zero, null/empty string input...)
            decimal rv;
            int numerator, denominator, wholePart = 0;
            int sign = 1;

            if (string.IsNullOrEmpty(frac))
                return 0m;

            // deal with signs
            frac = frac.Trim().TrimStart('+');
            if (frac[0] == '-')
            {
                frac = frac.TrimStart('-');
                sign = -1;
            }
            frac = frac.Trim();

            if (frac.IndexOf("/") > 0)
            {
                if (frac.IndexOf(" ") > 0)
                {
                    wholePart = int.Parse(frac.Substring(0, frac.IndexOf(" ")));
                    frac = frac.Substring(frac.IndexOf(" "));
                }
                numerator = int.Parse(frac.Substring(0, frac.IndexOf("/")));
                denominator = int.Parse(frac.Substring(frac.IndexOf("/") + 1));
                rv = sign * (wholePart + ((decimal)numerator / denominator));
            }
            else
            {
                rv = decimal.Parse(frac);
            }
            return rv;
        }

        public static string DecimalToFractionSigned(decimal value)
        {
            // always put a sign (+/-) in front
            string rv = DecimalToFraction(value);
            if (rv[0] != '-')
                rv = string.Format("+{0}", rv);
            return rv;
        }

        public static string DecimalToFraction(decimal value)
        {
            // taken from here: http://bit.ly/tHaKrK and modified to work with negative numbers too.

            int sign = 1;
            if (value < 0)
            {
                value = Math.Abs(value);
                sign = -1;
            }

            // get the whole value of the fraction
            decimal mWhole = Math.Truncate(value);

            // get the fractional value
            decimal mFraction = value - mWhole;

            // initialize a numerator and denominator
            uint mNumerator = 0;
            uint mDenominator = 1;

            // ensure that there is actually a fraction
            if (mFraction > 0m)
            {
                // convert the value to a string so that you can count the number of decimal places there are
                string strFraction = mFraction.ToString().Remove(0, 2);

                // store the number of decimal places
                uint intFractLength = (uint)strFraction.Length;

                // set the numerator to have the proper amount of zeros
                mNumerator = (uint)Math.Pow(10, intFractLength);

                // parse the fraction value to an integer that equals [fraction value] * 10^[number of decimal places]
                uint.TryParse(strFraction, out mDenominator);

                // get the greatest common divisor for both numbers
                uint gcd = GreatestCommonDivisor(mDenominator, mNumerator);

                // divide the numerator and the denominator by the greatest common divisor
                mNumerator = mNumerator / gcd;
                mDenominator = mDenominator / gcd;
            }

            // create a string builder
            StringBuilder mBuilder = new StringBuilder();

            // add the whole number if it's greater than 0
            if (mWhole > 0m)
            {
                mBuilder.Append(mWhole);
            }

            // add the fraction if it's greater than 0m
            if (mFraction > 0m)
            {
                if (mBuilder.Length > 0)
                {
                    mBuilder.Append(" ");
                }

                mBuilder.Append(mDenominator);
                mBuilder.Append("/");
                mBuilder.Append(mNumerator);
            }

            if (sign == -1)
                mBuilder.Insert(0, '-');

            return mBuilder.ToString();
        }


        private static uint GreatestCommonDivisor(uint valA, uint valB)
        {
            // return 0 if both values are 0 (no GSD)
            if (valA == 0 && valB == 0)
            {
                return 0;
            }
            // return value b if only a == 0
            else if (valA == 0 && valB != 0)
            {
                return valB;
            }
            // return value a if only b == 0
            else if (valA != 0 && valB == 0)
            {
                return valA;
            }
            // actually find the GSD
            else
            {
                uint first = valA;
                uint second = valB;

                while (first != second)
                {
                    if (first > second)
                    {
                        first = first - second;
                    }
                    else
                    {
                        second = second - first;
                    }
                }

                return first;
            }
        }

    }
}

(This is also in a Gist.)
I hope this helps anyone who might be looking for something similar. Also, I want to reiterate that I didn’t write this code from scratch. I took two existing functions, one in VB and one in C#, converted the VB to C#, cleaned them both up a bit, and put them together.

Luckily, by the way, all of the fractions I’m dealing with resolve to simple decimal numbers; everything is x/2, x/4, or x/8. I don’t have to deal with converting 1/3 to decimal and back. If you need to do that, you probably want a class that stores the fractions as numerator and denominator, and does math on them, as fractions.  There are a couple of those out there, if you look around.

Steve Jobs – 1985

I recently finished reading a long interview with Steve Jobs that was published in Playboy back in 1985. You can find a text version of it here or read it at Playboy.com here. Some of the stuff in the interview is kind of funny, in retrospect. Some other stuff is a little heartbreaking, for obvious reasons. My favorite part of the interview is when they started talking about the future of computing:

PLAYBOY: What will change?

JOBS: The most compelling reason for most people to buy a computer for the home will be to link it into a nationwide communications network. We’re just in the beginning stages of what will be a truly remarkable breakthrough for most people—as remarkable as the telephone.

PLAYBOY: Specifically, what kind of breakthrough are you talking about?

JOBS: I can only begin to speculate. We see that a lot in our industry: You don’t know exactly what’s going to result, but you know it’s something very big and very good.

PLAYBOY: Then for now, aren’t you asking home-computer buyers to invest $3000 in what is essentially an act of faith?

JOBS: In the future, it won’t be an act of faith. The hard part of what we’re up against now is that people ask you about specifics and you can’t tell them. A hundred years ago, if somebody had asked Alexander Graham Bell, “What are you going to be able to do with a telephone?” he wouldn’t have been able to tell him the ways the telephone would affect the world. He didn’t know that people would use the telephone to call up and find out what movies were playing that night or to order some groceries or call a relative on the other side of the globe. But remember that first the public telegraph was inaugurated, in 1844. It was an amazing breakthrough in communications. You could actually send messages from New York to San Francisco in an afternoon. People talked about putting a telegraph on every desk in America to improve productivity. But it wouldn’t have worked. It required that people learn this whole sequence of strange incantations, Morse code, dots and dashes, to use the telegraph. It took about 40 hours to learn. The majority of people would never learn how to use it. So, fortunately, in the 1870s, Bell filed the patents for the telephone. It performed basically the same function as the telegraph, but people already knew how to use it. Also, the neatest thing about it was that besides allowing you to communicate with just words, it allowed you to sing.

In praise of impractical programming

Here’s a great little article from Nieman Journalism Lab on impractical programming.

All that matters is that you strike out on journeys without clear destinations in lands you hardly know. Be impractical. Cast spells.

iOS programming

I’m more than half-way through my iOS programming class at NYU. I’ve missed one class due to a flat tire, and I’ve been a bit under the weather during a couple of classes, but I’m definitely getting something out of the class.
I’ve made a Hypotrochoid generator the basis for my previous two homework assignments, so that’s been kind of fun. I didn’t figure out the code for this myself. Rather, I took the C# code found here, and converted it to Objective-C / Cocoa.
All of my homework code is up on my Github page, if anyone wants to look at it for some reason.
And here’s a quick screencast of my app. Not that exciting really, but fun to write.

Kindle e-book lending

Interesting to see that Amazon is now letting Prime members borrow e-books. Only one at a time, and from a limited selection, but it’s a start. I bought four e-books yesterday from Amazon, all $1.99 or $2.99, and I probably have 30 or 40 unread books on my Kindle right now anyway, so I don’t have much need for this program at this point. But I like where they’re going with Amazon Prime.

Dark Horse

I’ve bought a few digital comics via the Comixology iPad app over the last year, but I hadn’t bought any through the Dark Horse app until today. I just bought the new Groo mini-series (which apparently came out in print in 2009), and a Classic Usagi Yojimbo mini-series, which may be a digital-only release. The bundle pricing on these books is pretty reasonable, but you can only buy the bundles through the web site, not the app.
I’ve found myself reading comics on the iPad a lot recently, mostly while I’m on the train. I should really be working my way through the Programming iOS 4 ebook that I started a while ago, but I’ve been finding that my brain isn’t really up for that sometimes.
One interesting comic I’ve been reading via Comixology recently is Vision Machine. The whole three-issue series is completely free. It originally came out just about one year ago, and there was a panel about it at last year’s NYCC, moderated by Andy Ihnatko.

iOS 5

I haven’t updated either my iPhone or iPad to iOS 5 yet, but, as a programmer, I’m happy to see that they’re finally doing automatic reference counting in Objective-C. I’m wondering if the instructor for my NYU iOS class is going to work any iOS 5 stuff into the class or not.  I could see where it would be hard to update class materials on the fly for this stuff, and our classroom iMacs probably still haven’t been updated to the latest version of XCode, but I’m hopeful.

off to NYCC 2011

I’m heading out to NYCC tomorrow. I’m pretty sure that the last con I went to was NYCC 2009, which was back in February 2009, before they moved the con to the fall. I had plans to go to NYAF in 2009 also, which would have been in September, but my Dad was in the hospital at that time, so I skipped it. So I haven’t been to a con in a while.

I was also thinking that I haven’t really taken a vacation (other than a long weekend) in a while either. I guess that NYCC in Feb 2009 was the last time, though I think I only took Friday off for that, so that would also have just been a long weekend. This time, I’m taking Thursday, Friday, and Monday off, but I’ve got class at NYU on Thursday night, and a doctor’s appointment back in NJ on Monday, so I don’t know if this really counts as more than a long weekend.

The last San Diego show I went to was 2008. For SDCC, I would have flown out on Wednesday, come back on Monday, and I probably took Tuesday off to do laundry and relax, so that’s a solid seven days away from work. So July 2008 was likely the last serious vacation I had, which involved leaving the NY/NJ area, and staying away for more than a few days. And I can’t remember the last time I took a whole work week, Monday to Friday, off and had a good full nine days away from work. Technically, I wasn’t working at all during April 2010, in between leaving NMS/Spar and starting at Electric Vine, but there was enough going on then that it sure didn’t feel like a vacation.

So this long blog post that was going to be about NYCC 2011 has turned into a rumination on my lack of time off over the last few years. I’m going to have to come up with a plan to remedy that, though I’m really not that enthusiastic about any particular vacation idea right now. I’d like to get back to SDCC and/or WonderCon next year, so maybe I should look at that as my goal.

RIP Steve

So sad to hear of Steve Jobs passing tonight. Only 56 years old. I’m starting an iOS dev class at NYU tomorrow night. That first class is going to feel a little weird now. I remember, years ago, being kind of mad at Steve for killing off the Newton, and its OS. It took a while to get from the Newton to where we are now with iOS, the iPhone, iPad, and iPod Touch, but we wouldn’t have gotten here without Steve Jobs. And I have to grudgingly admit that killing the Newton was probably the right decision. Sorry Steve.