3

Ok so this is kind of weird. I have an algorithm to find the highest possible numerical palindrome that is a multiple of two factors who each have K digits.

The method I'm using to find the highest valid palindrome is to look at the highest possible palindrome for the number set (i.e. if k=3, the highest possible is 999999, then 998899, etc). Then I check if that palindrome has two factors with K digits.

For debugging, I thought it would be a good idea to print to the console each of the palindromes I was checking (to make sure I was getting them all. To my surprise, adding

Console.WriteLine(palindrome.ToString());

to each iteration of finding a palindrome dropped my runtime a whopping 10 seconds from ~24 to ~14.

To verify, I ran the program several times, then commented out the Console command and ran that several times, and every time it was shorter with the Console command.

This just seems weird, any ideas?

Here's the source if anyone wants to take a whack at it:

    static double GetHighestPalindromeBench(int k)
    {
        //Because the result of k == 1 is a known quantity, and results in aberrant behavior in the algorithm, handle as separate case
        if (k == 1)
        {
            return 9;
        }


        /////////////////////////////////////
        //These variables will be used in HasKDigitFactors(), no need to reprocess them each time the function is called
        double kTotalSpace = 10;

        for (int i = 1; i < k; i++)
        {
            kTotalSpace *= 10;
        }

        double digitConstant = kTotalSpace;  //digitConstant is used in HasKDigits() to determine if a factor has the right number of digits

        double kFloor = kTotalSpace / 10; //kFloor is the lowest number that has k digits (e.g. k = 5, kFloor = 10000)

        double digitConstantFloor = kFloor - digitConstant;  //also used in HasKDigits()

        kTotalSpace--;  //kTotalSpace is the highest number that has k digits (e.g. k = 5, kTotalSpace = 99999)

        /////////////////////////////////////////


        double totalSpace = 10;

        double halfSpace = 10;

        int reversionConstant = k;

        for (int i = 1; i < k * 2; i++)
        {
            totalSpace *= 10;
        }

        double floor = totalSpace / 100;

        totalSpace--;


        for (int i = 1; i < k; i++)
        {
            halfSpace *= 10;
        }

        double halfSpaceFloor = halfSpace / 10;    //10000

        double halfSpaceStart = halfSpace - 1;     //99999

        for (double i = halfSpaceStart; i > halfSpaceFloor; i--)
        {
            double value = i;
            double palindrome = i;
            //First generate the full palindrome
            for (int j = 0; j < reversionConstant; j++)
            {
                int digit = (int)value % 10;

                palindrome = palindrome * 10 + digit;

                value = value / 10;
            }

            Console.WriteLine(palindrome.ToString());
            //palindrome should be ready
            //Now we check the factors of the palindrome to see if they match k
            //We only need to check possible factors between our k floor and ceiling, other factors do not solve
            if (HasKDigitFactors(palindrome, kTotalSpace, digitConstant, kFloor, digitConstantFloor))
            {
                return palindrome;
            }
        }


        return 0;
    }

    static bool HasKDigitFactors(double palindrome, double totalSpace, double digitConstant, double floor, double digitConstantFloor)
    {
        for (double i = floor; i <= totalSpace; i++)
        {
            if (palindrome % i == 0)
            {
                double factor = palindrome / i;
                if (HasKDigits(factor, digitConstant, digitConstantFloor))
                {
                    return true;
                }
            }
        }
        return false;
    }

    static bool HasKDigits(double value, double digitConstant, double digitConstantFloor)
    {
        //if (Math.Floor(Math.Log10(value) + 1) == k)
        //{
        //    return true;
        //}
        if (value - digitConstant > digitConstantFloor && value - digitConstant < 0)
        {
            return true;
        }

        return false;
    }

Note that I have the Math.Floor operation in HasKDigits commented out. This all started when I was trying to determine if my digit check operation was faster than the Math.Floor operation. Thanks!

EDIT: Function call

I'm using StopWatch to measure processing time. I also used a physical stopwatch to verify the results of StopWatch.

        Stopwatch stopWatch = new Stopwatch();
        stopWatch.Start();
        double palindrome = GetHighestPalindromeBench(6);
        stopWatch.Stop();

        TimeSpan ts = stopWatch.Elapsed;

        string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}:{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10);

        Console.WriteLine();
        Console.WriteLine(palindrome.ToString());
        Console.WriteLine();
        Console.WriteLine(elapsedTime);
Tevis
  • 729
  • 1
  • 12
  • 27
  • 1
    How are you measuring? – Ry- May 31 '14 at 00:04
  • 2
    Are both run in Debug mode or in Release mode ? What .NET version ? Wehre do you measure this ? You dont show the code for the measure. – quantdev May 31 '14 at 00:04
  • 1
    It is really a big guess : maybe because you are writing to IO your thread gets more processor time because WriteLine is synchronized and thus blocking other threads. – ForguesR May 31 '14 at 00:11
  • Edited with the function call. Thanks! – Tevis May 31 '14 at 00:13
  • @ForguesR Good idea! That very well could be it. Still seems rather strange though – Tevis May 31 '14 at 00:14
  • @karim Both running in Debug mode, .NET 4.5 – Tevis May 31 '14 at 00:19
  • and how do you meaasure it ? how often did you run this test ? – quantdev May 31 '14 at 00:30
  • @karim Measured using Stopwatch (see edit) and I've run the test about 20 times each with and without the Console.WriteLine, all with the same result. Edit: I should say with Console.WriteLine in it's always 10 seconds faster than it is without – Tevis May 31 '14 at 00:34
  • Do you have the same function result in all cases ? Are there other threads running in this program ? – quantdev May 31 '14 at 00:39
  • @Tevis, I'm not getting the same results as you. Without the console output, it runs about 30ms faster every time. – LVBen May 31 '14 at 00:41
  • @karim Yes the result is always the same. For each input value k (and I'm keeping it constant for testing) the algorithm follows exactly the same steps and achieves the exact same result. There are no other threads running, it's a simple Command-line application, and this is the only function call, except for Stopwatch. – Tevis May 31 '14 at 00:42
  • @LVBen that's interesting, are you running it in a console application? – Tevis May 31 '14 at 00:44
  • So, you are running 20 times the test with (20 different debug run in Visual Studio) and then 20 without ? Can you show us the output of the console and the stopwatch (edit your question) – quantdev May 31 '14 at 00:45
  • @Tevis Yes, indeed! I'm using .net 4.0 with VS 2010. I'll try with 4.5. – LVBen May 31 '14 at 00:46
  • @Tevis Nearly identical results with VS 2013 and .net 4.5. – LVBen May 31 '14 at 00:50
  • Can you check the thread priority with and without the WriteLine? Just want to make sure it is the same... – ForguesR May 31 '14 at 01:00
  • On my system (dual core with hyperthreading), running Windows 8.1 and Visual Studio 2013 (.NET 4.5), the version with the `Console.WriteLine` calls is slightly (about 1 second) slower. This is true in debug and release modes, with or without the debugger attached. Speculation is that the console output is buffered by the OS, and the actual writes take place concurrently with processing. – Jim Mischel May 31 '14 at 01:26
  • @ForguesR See my question: http://stackoverflow.com/questions/37119554/console-writeline-speeds-up-my-code I believe your comment was correct in my situation – TheLethalCoder Aug 02 '16 at 16:21
  • Possible duplicate of [Console.WriteLine speeds up my code?](http://stackoverflow.com/questions/37119554/console-writeline-speeds-up-my-code) – TheLethalCoder Jan 13 '17 at 14:28

1 Answers1

4

I have tested your code. My system is an i7-3770 3.40 GHz, quad-core with hyperthreading, so 8 cores available.

Debug build, with and without the console Writeline statement (commented out or not), in debug mode or not, the times vary from about 8.7 to 9.8 sec. As a Release build it comes down to about 6.8-7.0 sec either way. Th figures were the same inside VS and from the command line. So your observation is not reproduced.

On performance monitor with no console output I see one core at 100%, but it switches between cores 1,4,5 and 8. Without console output there is activity on other cores. Max CPU usage never exceeds 18%.

In my judgment your figure with console output is probably consistent with mine, and represents the true value. So your question should read: why is your system so slow when it's not doing console output?

The answer is: because there is something different about your computer or your project which we don't know about. I've never seen this before, but something is soaking up cycles and you should be able to find out what it is.

I've written this as an answer although it isn't really an answer. If you get more facts and update your question, hopefully I can provide a better answer.

david.pfx
  • 10,520
  • 3
  • 30
  • 63