开发者

Is it more efficient to compare ints and ints or strings and strings

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)) {开发者_如何学Go }

OR

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


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();
        }
    }
}


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.


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))


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.


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?


My case that brought me here was to check if "5" == 5 in a switch-case and because I will always receive numbers between 0 and 9 I found out that the fastest way is: (int)b[0] == 53 So I'm taking the fist character of string "5" (b[0]) and cast it to it ACSII value which is 53 and after that compare. Here are the results: a == int.Parse(b) milliseconds: 194 a.ToString() == b milliseconds: 142 a == (int)(b[0]) milliseconds: 8 Even though it is very unusual case the difference on a massive array is obvious;

EDIT: As Dirk Horsten requested. Wrong as I am. I mentioned in my post that I use that on a switch case so I will use in all of my cases the ASCII values so it will look like that: switch((int)b[0]) { case 48: Console.WriteLine("0"); break; case 49: Console.WriteLine("1"); break; case 50: Console.WriteLine("2"); break; case 51: Console.WriteLine("3"); break; case 52: Console.WriteLine("4"); break; case 53: Console.WriteLine("5"); break; case 54: Console.WriteLine("6"); break; case 55: Console.WriteLine("7"); break; case 56: Console.WriteLine("8"); break; case 57: Console.WriteLine("9"); break; } And for a good order sake here are the results as you asked me: a == int.Parse(b) milliseconds: 184 a.ToString() == b milliseconds: 135 a + 48 ==(int)b[0] milliseconds: 8 As you could see there is no such a big difference just adding one addition.


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.


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.


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

StringA.ToUpperInvariant() == StringB.ToUpperInvariant()


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))
{

}


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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜