views:

379

answers:

10

I've got a program written in c# where there are a lot of comparisons between ints and strings.

So for performance reasons I would just like to know which is more efficient?

If we have:

int a  = 5;
string b = "5";

if(a == int.Parse(b))
{

} 

OR

if(a.ToString() == b)
{

}
+1  A: 

The larger the number I'll go for the first method. a. if b is not a number, it will failed before trying to compare. b. string are compared by the length and number at once.

Dani
A: 

Parsing a String to an Int32 requires more performance and is more sensitive to errors. You will have to make sure the Int32.Parse will be successful in the first place. Also you can use an alternative for '=='. Use .Equals(), this easier to read and understand.

if(b.Equals(a))
{

}
D. Veloper
1.Equals("1") will compile, but return false. This is not what he wants.
Freed
+4  A: 

A few comments mentioned running a profiling tool to prove which has better performance.

This is a ok, but the simplest way to check performance of specific statements is to put them in a loop and use the Stopwatch class.

Jeff Atwood asked about making this sort of timing even simpler in this question. In that question and answer you will also find some good code examples and background details.

Heres a very simple working example:

 System.Diagnostics.Stopwatch sw=new System.Diagnostics.Stopwatch();


 int a  = 5;
 string b = "5";

 sw.Start();

 for (int i=0;i<1000000;i++)
 {
  if(a == int.Parse(b))
  {

  } 
 }

 sw.Stop();

 Console.WriteLine("a == int.Parse(b) milliseconds: " + sw.ElapsedMilliseconds);

 sw.Reset();

 sw.Start();

 for (int i=0;i<1000000;i++)
 {
  if(a.ToString() == b)
  {

  }  
 }  

 sw.Stop();

 Console.WriteLine("a.ToString() == b milliseconds: " + sw.ElapsedMilliseconds);

On my computer it outputs:

a == int.Parse(b) milliseconds: 521

a.ToString() == b milliseconds: 697

So in this simple scenario int.Parse() is slightly faster, but not enough to really worry about.

Ash
is that the Debug Stopwatch Class? soz im a bit of a newbie when it comes to c# :)
The_Butcher
It's the System.Diagnostics.Stopwatch class. You should be able to just type: Stopwatch sw=new Stopwatch(); and begin usng it (it's in System.dll).
Ash
+1, this is not a case for using a "real" profiler.
Freed
1000000 runs => difference less than 200ms. This may not be a case for an optimisation. If the queries are slow, use a profiler. If they are fast enough, why would you waste time optimising ?
Guillaume
Any reason you're starting the stopwatch twice for the first round, including the variable assignment? Shouldn't be large enough to skew the results, but still...
Freed
@Freed, because I was typing faster then my brain could follow ;) nice pick-up! I've removed the first Start().
Ash
Can you try the string as a hexadecimal? I'm surprised (I'm not doubting the result though) that it's faster considering all the logic int.Parse has to perform
Chris S
@Chris, isn't the logic that ToString() has to perform very much alike what Parse() needs to do..?
Freed
Stop micro-optimizing!
SeanJA
If you try ToString("D") it may be quicker. This uses the Int32ToDecStr function in the CLR. No format (just ToString()) is equivalent to "G" which uses NumberToString() which parses a format. So @freed yes I'm wrong above
Chris S
ToString("D") is no quicker at all. string.Format("{0:D}",a) is a lot slower
Chris S
A: 

Also i read somwhere (MSDN) using the following is faster than == for string comparisons

StringA.ToUpperInvariant() == StringB.ToUpperInvariant()
What is the benefit of using upper case when comparing numbers?
Kobi
The same if it were strings?
http://msdn.microsoft.com/en-us/library/ms973919.aspx
Moreover, it's faster to use an Equals with OrdinalIgnoreCase (or InvariantCultureIgnoreCase) than allocating new uppercase strings.
Guillaume
A: 

There are many ways of representing the same number as a string...

ima
+7  A: 

I actually profiled this using a few examples and timed loops. It turns out Parse wins for small integers, and ToString wins for large ones. This difference is so small it should not be a concern however, as others have mentioned, you're likely to make a better choice by thinking about the cases where the string does not represent an integer at all.

Edit: For those interested, here's the source, quick 'n' dirty:

using System;
using System.Diagnostics;

namespace CompareTest
{
    static class Program
    {
        static void Main(string[] args)
        {
            int iterations = 10000000;
            int a = 5;
            string b = "5";

            Stopwatch toStringStopwatch = new Stopwatch();
            toStringStopwatch.Start();

            for (int i = 0; i < iterations; i++) {
                bool dummyState = a.ToString() == b;
            }

            toStringStopwatch.Stop();

            Stopwatch parseStopwatch = new Stopwatch();
            parseStopwatch.Start();

            for (int i = 0; i < iterations; i++) {
                bool dummyState = a == int.Parse(b);
            }

            parseStopwatch.Stop();

            Console.WriteLine("ToString(): {0}", toStringStopwatch.Elapsed);
            Console.WriteLine("Parse(): {0}", parseStopwatch.Elapsed);
            Console.ReadLine();
        }
    }
}
Freed
thanks for that!
The_Butcher
+4  A: 

Your choice is between the following
Code Listing A

int a = 5;
string b = "5";
//Assuming these two values are input received by the application at runtime
int bInt;
if (int.TryParse(b, NumberStyles.None, CultureInfo.InvariantCulture, out bInt) 
    && a.Equals(bInt))
{

}

and

Code Listing B

int a = 5;
string b = "5"; 
//Assuming these two values are input received by the application at runtime
if (string.Compare(b, a.ToString(), StringComparison.Ordinal) != -1)
{

}

I have tested this with stopwatch (as given in the selected answer) and found Code Listing A to be much faster. But Code Listing B is more readable!

Code Listing A beats if(a == int.Parse(b))

Binoj Antony
+1  A: 

I doubt either call will really significantly impact your application unless you really are creating something on a grand scale.

Both techniques are creating a new string, however int.ToString() has to perform a lot less tasks than int.Parse().

int.ToString() is performed internally in the CLR (comnumber). int.Parse() is done inside the BCL source using Number.ParseInt32() -> Number.StringToNumber() -> Number.ParseNumber().

ParseNumber performs a huge number of checks so from a finger in the air guess you would imagine int.ToString() is faster. As others have mentioned, a proper performance test with the StopWatch class will be a better way to find out. You will want to try this out with the number format you are expecting: decimal, hex.

You can compare the C++ that the CLR is using for ToString() here: Look for

  • NumberToString (that's used for ToString() and other formats) which is used in FCIMPL3, called by int.ToString() as an extern call.
  • Int32ToDecStr is used for the "D" formatter.

The C#

var x = 5.ToString("D");
var y = 5.ToString();

I could be wrong about FCIMPL3, please correct me if I am.

Chris S
+3  A: 

Internally, ToString and Parse do the following:

Parse

value = 0
for each char in string
  value = value * 10 + valueof(char) // i.e. '0' -> 0, '7' -> 7

ToString

string=""
while value > 0
  string.insert_at_front value % 10 // so that 0 -> '0' and 6 -> '6'
  value /= 10

// on IA32, the % and / can be done at the same time but requires
// a 64bit source for 32bit values

The ToString should be slower than Parse since division is generally slower than multiplication. However, the above doesn't take into account any overhead the Parse and ToString functions might perform during the conversion (i.e. generating exceptions, allocating memory), which means it's not as clear-cut which will more optimal.

From the other answers it seems the difference is marginal anyway so just use whatever make more sense to you.

Skizz
+2  A: 

You've already gotten a few good responses, but let me add a couple of small points.

  1. One of the well-known risks with micro-benchmarks is that a small number of repetitions can end up measuring noise (e.g. the timings can be skewed by an incoming email or IM), but a large number of repetitions can end up measuring the performance of your garbage collector (e.g. if your code is constantly creating and discarding strings).

  2. When I find myself in an awkward spot in code, it's sometimes helpful to ask myself, "What assumptions or choices put me in this situation? What could I do differently?" For example (just guessing), when you wrote "...where there are a lot of comparisons between int's*[sic]* and strings", does that imply that you may be using the same values repeatedly (e.g., comparing new values against previous values)? If so, could you convert each string to int, and cache the converted value for subsequent re-use, instead of having to convert it again later?

joel.neely