tags:

views:

1356

answers:

8

I was refactoring some old code and came across the following line of code to convert bytes to GB.

decimal GB = KB / 1024 / 1024 / 1024;

Is there a better way to refactor the following piece of code?

Update

I meant to say bytes to Gigabytes. I gave wrong information.

+12  A: 

If exact precision is not important, use double:

double gb = kb / 1048576D

Agree with Pavel here - there's not really any need to refactor this code... in fact, if this is the biggest problem in your codebase, I think you might be sitting on the most well-written software ever.

Rex M
+1 on the use of double, but I think the original implementation's intent is clearer.
Marc
@Marc probably. I think the gb = kb... part is a pretty good clue though :)
Rex M
you could probably improve the readability of the value 1048576 by declaring it as a constant with an intent revealing name...
mezoid
+2  A: 

Personally I'd write it like this: decimal GB = KB / (1024 * 1024); but there's really no need to refactor the code as written.

mattnewport
+4  A: 

The original code is succinct, easy to read, and with reasonable variable names, self-documenting; I wouldn't change it.

If you absolutely must refactor, you could create a set of extension methods on the numeric types:

public static double BytesToKilobytes(this Int32 bytes)
{
    return bytes / 1024d;
}
public static double BytesToMegabytes(this Int32 bytes)
{
    return bytes / 1024d / 1024d;
}
public static double KilobytesToBytes(this double kilobytes)
{
    return kilobytes * 1024d;
}

//You can then do something like:
double filesize = 32.5d;
double bytes = filesize.KilobytesToBytes();

But unless your code does virtually nothing but convert bytes to kilobytes etc, all this will really do is clutter up Intellisense for no real gain.

technophile
+2  A: 

Well, the formula is wrong (there's only about a million kilobytes in a gigabyte, not a thousand million) but, other than that, it's fine. Anyone used to working with these numbers will know what it means.

One thing I would watch out for (and I don't know if this is a problem with C#) is that a compiler may not be able to optimize the x/1024/1024 if x is not a basic type. With C and integers, the compiler would quite easily turn that into a "blindingly-fast-shift-right-by-20-bits" instruction.

If decimal is a class rather than a basic type, the compiler may have to do two divide operations. Whether this has any real impact on speed (or even whether it happens at all) is outside of my sphere of knowledge.

One thing I'd consider changing is the actual variable names. It makes no real difference to the compiled code but I prefer longer variable names rather than abbreviations, so I'd opt for kiloBytes/gigaBytes or something like that. KB/GB is too easy to get confused with constants, depending on your coding standards.

paxdiablo
A: 

To make sure that the compiler pre-calculates the divisors:

decimal GB = KB / (1024 * 1024);

Note that you are actually calculating GiB (gibibyte), not GB (gigabyte). If you really want to calculate GB, that would be:

decimal GB = KB / (1000 * 1000);
Guffa
In general usage, gigabyte is used to refer to 1024^3 bytes, mega for 1024^2, kilo for 1024. It may not be technically correct, but I don't think anyone (else) here minds.
Snarfblam
Yes, most people are not aware of the standard eventhough it's been around for more than ten years, that's why I made a note about it...
Guffa
The "standard" is merely no real one, since it changed the common meanings of the words and created new words for common things. Thats why really no one accepts this standard, appart from the industry that made it.
BeowulfOF
@BeowulfOF: What you say is not true. I have seen several programs using the standardised units. It's a real standard, defined by IEC and accepted by several large standardisation bodies like IEEE and CIPM. The standard did not change the commmon meaning of the units as there was no common meaning. Take for example the case of "1.44 MB" floppy disks, where the capcaity was neither 1.44 MB nor 1.44 MiB, but 1.44 * 1024 * 1000 bytes...
Guffa
+1  A: 

In theory, this is faster (precomputing the constant to do multiplication instead of division). It's probably not used often enough to matter, but just in case.

double const KbToGbFactor = 1d / 1024 /1024;

double gb = kb * KbToGbFactor;
kek444
I'm pretty sure this will be optimized when the program is compiled. It is more a matter of taste though whether or not you want a const here.
Spoike
I'm not so sure - http://blogs.msdn.com/ericlippert/archive/2009/06/11/what-does-the-optimize-switch-do.aspx
kek444
I like this answer for "clarity" (in my mind), but not for "optimization". Uhg :-)
pst
+6  A: 

I developed this method here, works up to TB.

private string formatBytes(float bytes)
    {
        string[] Suffix = { "B", "KB", "MB", "GB", "TB" };
        int i;
        double dblSByte=0;
        for (i = 0; (int)(bytes / 1024) > 0; i++, bytes /= 1024)
            dblSByte = bytes / 1024.0;
        return String.Format("{0:0.00} {1}", dblSByte, Suffix[i]);
    }
JLopez
+1  A: 
    /// <summary>
/// Function to convert the given bytes to either Kilobyte, Megabyte, or Gigabyte
/// </summary>
/// <param name="bytes">Double -> Total bytes to be converted</param>
/// <param name="type">String -> Type of conversion to perform</param>
/// <returns>Int32 -> Converted bytes</returns>
/// <remarks></remarks>
public static double ConvertSize(double bytes, string type)
{
    try
    {
        const int CONVERSION_VALUE = 1024;
        //determine what conversion they want
        switch (type)
        {
            case "BY":
                 //convert to bytes (default)
                 return bytes;
                 break;
            case "KB":
                 //convert to kilobytes
                 return (bytes / CONVERSION_VALUE);
                 break;
            case "MB":
                 //convert to megabytes
                 return (bytes / CalculateSquare(CONVERSION_VALUE));
                 break;
            case "GB":
                 //convert to gigabytes
                 return (bytes / CalculateCube(CONVERSION_VALUE));
                 break;
            default:
                 //default
                 return bytes;
                 break;
          }
     }
     catch (Exception ex)
     {
         Console.WriteLine(ex.Message);
         return 0;
      }
}

/// <summary>
/// Function to calculate the square of the provided number
/// </summary>
/// <param name="number">Int32 -> Number to be squared</param>
/// <returns>Double -> THe provided number squared</returns>
/// <remarks></remarks>
public static double CalculateSquare(Int32 number)
{
     return Math.Pow(number, 2);
}


/// <summary>
/// Function to calculate the cube of the provided number
/// </summary>
/// <param name="number">Int32 -> Number to be cubed</param>
/// <returns>Double -> THe provided number cubed</returns>
/// <remarks></remarks>
public static double CalculateCube(Int32 number)
{
     return Math.Pow(number, 3);
}

//Sample Useage
String Size = "File is " + ConvertSize(250222,"MB") + " Megabytes in size"
Aizaz