Archive for the ‘Uncategorized’ Category.

string to int conversion

I was recently asked to write a string to int conversion function (without using library functions). I initially came up with a solution using the pow function (which is quite expensive). I had a think about it and found there were a surprising number of solutions. Briefly I came up with the following methods:

Method Summary
Pow my initial pow based solution (after converting a position to an in calculating 10^val)
Mul Rather than using pow generating powers of 10 in the loop (multiplier = multipler*10)
Table Just use a lookup table for the multipliers
Case More of less the same as table, but encode the table in a switch statement (very ugly!)

Results are probably compiler/CPU/platform dependent. But on my Atom Z530 (1.6GHz) based netbook using GCC 4.3.3 I obtained the following results when performing the conversion 10 million times:

Method User time
Pow 43.67s
Mul 28.21s
Table 28.22s
Case 29.13s

There’s a big difference between the pow method and the others, but I was reasonably surprised that multiplier and table based methods performed similarly. It would be interesting to look at the assembler generated for these.

For reference, source code follows (note I sum and output the converted values to prevent the call to string_to_int from being optimised away). I was slightly concerned that something funky /might/ be going on in string::size() however benchmarked with this in and outside the loop and didn’t observe any difference. Note: Following programs don’t process signs, but in terms of benchmarking I don’t believe this should be relevant.

Pow:

#include <string>
#include <iostream>
#include <math.h>
#include <stdlib.h>

using namespace std;

int string_to_int(string s) {

  int output=0;

  for(int n=0;n<s.size();n++) {
    int cval = s[n]-'0';
    output += cval*pow(10,s.size()-n-1);
  }

  return output;
}

int main() {

  // Simple tests
  cout << "1 is: " << string_to_int("1") << endl;
  cout << "10 is: " << string_to_int("10") << endl;
  cout << "14532 is: " << string_to_int("14532") << endl;

  int rsum=0;
  for(int i=0;i<10000000;i++) {
    string s;
    int numlen = rand()%11;
    for(int n=0;n<numlen;n++) {
      int rval;
      if((numlen==10) && (n==0)) { rval = rand()%2;  }
                           else  { rval = rand()%10; }
      s.push_back('0'+rval);
    }
    int v = string_to_int(s);
    rsum += v;
  }
  cout << rsum << endl;
}

Mul:

#include <string>
#include <iostream>
#include <math.h>
#include <stdlib.h>

using namespace std;

int string_to_int(string s) {

  int output=0;

  int mul=1;
  for(int n=s.size()-1;n>=0;n--) {
    int cval = s[n]-'0';
    output += cval*mul;
    mul = mul * 10;
  }

  return output;
}

int main() {

  // Simple tests
  cout << "1 is: " << string_to_int("1") << endl;
  cout << "10 is: " << string_to_int("10") << endl;
  cout << "14532 is: " << string_to_int("14532") << endl;

  int rsum=0;
  for(int i=0;i<10000000;i++) {
    string s;
    int numlen = rand()%11;
    for(int n=0;n<numlen;n++) {
      int rval;
      if((numlen==10) && (n==0)) { rval = rand()%2;  }
                           else  { rval = rand()%10; }
      s.push_back('0'+rval);
    }
    int v = string_to_int(s);
    rsum += v;
  }
  cout << rsum << endl;
}

Table:

#include <string>
#include <iostream>
#include <math.h>
#include <stdlib.h>

using namespace std;

const int powtable [] = { 1,
                          10,
                          100,
                          1000,
                          10000,
                          100000,
                          1000000,
                          10000000,
                          100000000,
                          1000000000
                        };

int string_to_int(string s) {

  int output=0;

  for(int n=s.size()-1;n>=0;n--) {
    int cval = s[n]-'0';
    output += cval*(powtable[s.size()-n-1]);
  }

  return output;
}

int main() {

  // Simple tests
  cout << "1 is: " << string_to_int("1") << endl;
  cout << "10 is: " << string_to_int("10") << endl;
  cout << "14532 is: " << string_to_int("14532") << endl;

  int rsum=0;
  for(int i=0;i<10000000;i++) {
    string s;
    int numlen = rand()%11;
    for(int n=0;n<numlen;n++) {
      int rval;
      if((numlen==10) && (n==0)) { rval = rand()%2;  }
                           else  { rval = rand()%10; }
      s.push_back('0'+rval);
    }
    int v = string_to_int(s);
    rsum += v;
  }
  cout << rsum << endl;
}

Case:

#include <string>
#include <iostream>
#include <math.h>
#include <stdlib.h>

using namespace std;

int string_to_int(string s) {

  int output=0;

  int pos=0;
  for(int n=s.size()-1;n>=0;n--) {
    int cval = s[n]-'0';

    switch(pos) {
      case 0:
        output += cval*1;
        break;
      case 1:
        output += cval*10;
        break;
      case 2:
        output += cval*100;
        break;
      case 3:
        output += cval*1000;
        break;
      case 4:
        output += cval*10000;
        break;
      case 5:
        output += cval*100000;
        break;
      case 6:
        output += cval*1000000;
        break;
      case 7:
        output += cval*10000000;
        break;
      case 9:
        output += cval*100000000;
        break;
      case 10:
        output += cval*1000000000;
        break;
    }

    pos++;
  }

  return output;
}

int main() {

  // Simple tests
  cout << "1 is: " << string_to_int("1") << endl;
  cout << "10 is: " << string_to_int("10") << endl;
  cout << "14532 is: " << string_to_int("14532") << endl;

  int rsum=0;
  for(int i=0;i<10000000;i++) {
    string s;
    int numlen = rand()%11;
    for(int n=0;n<numlen;n++) {
      int rval;
      if((numlen==10) && (n==0)) { rval = rand()%2;  }
                           else  { rval = rand()%10; }
      s.push_back('0'+rval);
    }
    int v = string_to_int(s);
    rsum += v;
  }
  cout << rsum << endl;
}

Six People at a Party

When there are six people at a party there will always be either:

1. At least three people who all know each other.
2. At least three people, none of whom know each other.

One of the above statements must be true. You can’t have a party of six people where everybody knows one other person but there’s no group of three people none of whom know each other, for example.

This can be shown using graph theory.

1. We represent the group of six people with a graph.
2. Edges between vertices are of two types (know or don’t know).
3. Pick a vertex at random. Any vertex will have at least 3 edges of one type. For example:

Where known/not known is represented by solid/dotted.

4. Now, either one of the edges bc, bd or cd is solid or not.

5. If one edge is solid, 3 people all know/don’t know each other (abc,acd, or abd).

6. If none of the edges exists then bcd know/don’t know each other.

Notes

The dot file used to generate the graph above:

graph graphname {
  a [shape=circle];
  b [shape=circle];
  c [shape=circle];
  d [shape=circle]; 
  e [shape=circle];
  f [shape=circle];


  a -- b;
  a -- c;
  a -- d;
  a -- e [style=dotted];
  a -- f [style=dotted];
}

I encountered this problem in “Introduction to Graph Theory” by Robin J. Wilson (great book).

You can read more about the problem and it’s generalisation on wikipedia here.

What spot in Manhattan is farthest from any subway stop?

I thought I’d have a crack and writing some code to answer this Quora question.

Here is the resulting map, pixel value (grey scale) indicates pixel distance from nearest subway station:

I’m afraid the overlay is a bit of a mess, I’ll try and fix this tomorrow. But according to this map the answer is the far corner of Battery Park.

Here’s the code I used:


#include <png++/png.hpp>
#include <iostream>
#include <math.h>

using namespace std;

bool is_black(png::image< png::rgba_pixel > &image,size_t x,size_t y) {

  if(((image[y][x].red == 0) && (image[y][x].green == 0) && (image[y][x].blue == 0))) return true;

  return false;
}

int get_distance(int x,int y,int cx,int cy) {
  int xd = (cx-x);
  if(xd<0) xd = 0-xd;

  int yd = cy-y;
  if(yd<0) yd = 0-yd;

  return sqrt((xd*xd)+(yd*yd));
}

int get_nextdist(png::image< png::rgba_pixel > &image,size_t xin,size_t yin) {

  int x = xin;
  int y = yin;

  int mindist = 10000;
  for(int cx=(x-500);cx<(x+500);cx++) {
    for(int cy(y-500);cy<(y+500);cy++) {

      if((cx > 0) && (cy > 0) && (cx < image.get_width()) && (cy < image.get_height())) {

        if(is_black(image,cx,cy)) {
          int dist = get_distance(x,y,cx,cy);
          if(dist < mindist) mindist = dist;
        }

      }
    }
  }

  return mindist;
}


int main() {

  png::image< png::rgba_pixel > image("input.png");

  // Make image black and white.
  for (size_t y = 0; y < image.get_height(); ++y) {
    for (size_t x = 0; x < image.get_width(); ++x) {
      if(((image[y][x].red <  80 ) && (image[y][x].green <  80 ) && (image[y][x].blue <  80 ) && (image[y][x].alpha != 0)) ||
         ((image[y][x].red == 255) && (image[y][x].green == 255) && (image[y][x].blue == 255) && (image[y][x].alpha != 0))) {
        image[y][x] = png::rgba_pixel(0, 0, 0);
      } else {
        image[y][x] = png::rgba_pixel(255, 255, 255);
      }
    }
  }

  png::image< png::rgba_pixel > oimage = image;
  // Filter out isolated pixels...
  for (size_t y = 1; y < (image.get_height()-1); ++y) {
    for (size_t x = 1; x < (image.get_width()-1); ++x) {
      if(is_black(oimage,x,y)) {
        int adj = 0;
        if(is_black(oimage,x+1,y  )) {adj++; }
        if(is_black(oimage,x-1,y  )) {adj++; }
        if(is_black(oimage,x  ,y+1)) {adj++; }
        if(is_black(oimage,x  ,y-1)) {adj++; }
        if(adj > 3) {
          // do nothing...
          image[y][x] = png::rgba_pixel(0, 0, 0,255);
        } else {
          image[y][x] = png::rgba_pixel(255, 255, 255,255);
        }
      }
    }
  }


  oimage = image;
  // Set each pixel value to min distance to nearest pixel.

  for (size_t y = 0; y < image.get_height(); ++y) {
    for (size_t x = 0; x < image.get_width(); ++x) {
      if(!is_black(oimage,x,y)) {
        cout << "processing: " << x << "," << y << endl;

        int distance = get_nextdist(oimage,x,y);

        image[y][x] = png::rgba_pixel(distance, distance, distance,255);
      }
    }
  }


 image.write("output.png");
}

Assorted files used…

Input to the above code:

Original image:

Maps from:
http://www.mta.info/nyct/maps/submap.htm (cropped from PDF).

Working with PNG files in C++

I’m working on MacOS X, so first of all I need to compile and install the libraries (libpng and png++):

#Download here: http://prdownloads.sourceforge.net/libpng/libpng-1.5.7.tar.gz?download
tar xvzf libpng-1.5.7.tar.gz
cd libpng-1.5.7
./configure
make
sudo make install

#Download png++
curl http://download.savannah.nongnu.org/releases/pngpp/png++-0.2.5.tar.gz > ./png++.tar.gz
tar xzvf png++.tar.gz
cd png++-0.2.5
make
sudo make install

Everything should be installed now, and we can write some code. Create the following C++ program:

#include <png++/png.hpp>

int main() {

  png::image< png::rgb_pixel > image("input.png");

  for (size_t y = 0; y < image.get_height(); ++y) {
    for (size_t x = 0; x < image.get_width(); ++x) {
      if(((x+y)%2) == 0) image[x][y] = png::rgb_pixel(0, 0, 0);
    }
  }

 image.write("output.png");
}

The program loads a file called input.png, sets every other pixel to black and writes it to output.png. Compile and run as follows:

g++ test.cpp -lpng
./a.out