Sunday, June 12, 2011

 

Russian Peasant Method of multiplication

Russian peasant method is one of the method I have used for multiplication of Integers over the years on processors that don't have explicit multiplication Instructions. Russian peasant method suits well because you just need instructions to double the number and halve the number, which is basically shift left and shift right respectively for a binary number. Almost all microprocessor will have these instructions and C language provides these operators << and >> respectively.

How it's done?

It is easy to explain the process with a diagram. Here it illustrates the multiplication of 5 x 4. RusianPeasentMethod
Step 1. If the multiplier is odd, add the multiplicand to the result. The red rows.
Step 2. Double the multiplicand.
Step 3. Halve the multiplier.
Step 4. Repeat step 1 to 3 till multiplier is zero.

You can switch the role of multiplicand and multiplier because of multiplication's commutative nature, doing so will reduce the number of iterations needed.

Here is the C code.

#include 

long multiply(int ml, int mp)
{
  long result =0;
   
  while( mp != 0)
  {
    if( mp & 01) /* if odd add ml to result */
    {
     result += ml;
     }
     ml <<= 1;
     mp >>= 1;
     
  }
  return result;
}

int main(void) 
{ 
  int x = 7;
  int y = 7;
  printf("%ld\n", multiply(x,y)); 
  return 0; 
} 

Labels:


Wednesday, May 25, 2011

 

Palindrome Puzzle

I heard this puzzle on car talk. It's about finding odometer reading which is a palindrome. The twist is that a 6 digit odometer read's palindrome in the morning when Tommy left to work and the odometer read palindrome again when Tommy came back home!

The complete detail is on Tommy's Drive to Work

To solve this problem

1. Find all 6 digit palindrome heuristically.
2. Sort all the palindrome in ascending order.
3. Compare  adjacent palindromes,  if they are less than 100(miles)  print the palindrome.

Here is my c++ solution

#include <iostream>
#include <vector>
#include <algorithm>
#include <iomanip>
 
// 5/25/2011 5:39 PM
// Car talk Puzzle 6 digit palindrome// Shankar Chakkere 
// http://www.cartalk.com/content/puzzler/transcripts/201121/index.html
 
std::vector <unsigned int > palindrome;
bool sortVector (unsigned int i,unsigned int j) { return (i < j);}
 
int main()
{
        // for 6 digit (654321) palindrome
        // digits 1 and 6 are same, 2 & 5 are same, 3 & 4 are same
        // e.g 175571
        
        // Generate all possible palindrome heuristically
        for(int x = 0; x <= 9; x++)
        {
                for(int y =0; y <= 9; y++)
                {
                        for(int z =0; z <= 9; z++)
                        {
                             
                                // Have not tried to optimize for sake of clarity
                                unsigned int pal = x*100000 + y*10000 + z*1000 + z*100 + y*10 + x;
                                palindrome.push_back(pal);
                               
                        }
                }
        }
        //
        // Sort them in ascending order
        std::sort(palindrome.begin(), palindrome.end(), sortVector);
        
        std::vector<unsigned int>::iterator it = palindrome.begin();
        unsigned int previous = *it++;
        while(it != palindrome.end())
        {
             unsigned int current = *it++;
             // if the diffence of adjacent odometer reading is less than 100 miles
             // assuming he does not drives more than 100 miles
             if( (current - previous) < 100)
             {
                std::cout << std::setw(6) << std::setfill('0') << previous << " " << current << " miles driven= " << current - previous << std::endl;
             }
             previous = current;
        }
        return 0;
}
 
The Output
099990 100001 miles driven= 11
199991 200002 miles driven= 11
299992 300003 miles driven= 11
399993 400004 miles driven= 11
499994 500005 miles driven= 11
599995 600006 miles driven= 11
699996 700007 miles driven= 11
799997 800008 miles driven= 11
899998 900009 miles driven= 11



Labels:


Monday, December 13, 2010

 

Code Brainstorm

Imagine you get a brainstorm to a  pressing software problem. You jot it down on a sheet of paper and you have itch to test it. You have a computer but don't have have the proper tools to test it.


If you have access to internet you can use one of many online IDE with multiple language support to test it.


To test and save source code snippets, I use ideone.com, but there are many like codepad.org for e.g.

The advantages are:

Labels:


Sunday, November 23, 2008

 

Anagram

Anagram is re-arranging the letters in the word such that it gives a different meaning word. Eg. syrup and pyres.

The problem is to  find all the anagrams in the english dictionary. The best solution I found is in the Jon Bentley's book  Programming Pearls  book.

Here is the algorithm:

Step 1 : Arrange each words in the dictionary in an order(Alphabetic), this gives the signature of the word.
Step 2 : Then sort these signature along with the word.
Step 3 : The words with the same signature are the anagrams.

words
signature( The word sorted in Alphabetical order)
signature with words,
Anagram, words with same signature
pal
alp
alp pal

lap
alp
alp  lap
pal lap
cat
act
act  cat



We will use the unix philosophy for solving this problem .

Unix philosophy states:
Write programs that do one thing and do it well. Write programs to work together. Write programs to handle text streams, because that is a universal interface.

We will write a  c++ program to generate the signature and the word pair, use the unix sort program to sort the signatures and use AWK script to extract the words with the same signature. The resulting words are the anagrams.

#include <iostream>
#include <fstream>
#include <string>
#include <iterator>
#include <algorithm>
bool charComp (char i, char j)
{
 return (i < j);
}
int main (int argc, char * const argv[])
{
 std::string signature;
 std::ifstream file;
 std::istream_iterator<std::string> inputItr;
 if(argc > 1)
 {
  file.open(argv[1]);
  inputItr = std::istream_iterator<std::string>(file);
 }
 else
 {
  inputItr = std::istream_iterator<std::string>(std::cin);
 }
 for (; inputItr != std::istream_iterator<std::string>(); inputItr++)
 {
   signature = *inputItr;
   // Sort the word in alphabetical order
   std::sort(signature.begin(), signature.end(), charComp);
   // Print the signature of the word and the word
   std::cout << signature << "  " << *inputItr   << std::endl;
 }
 return 0;
}
The program reads the words as the string either from file or through the standard input. Then sorts  each word alphabetically which makes the signature of the word and prints the signature and the word.

The sort program will sort the output of the program. It arranges the words with same signature next to each other. The command looks like this:

~ Shankar$ cat /usr/share/dict/words |tr [A-Z] [a-z]| ./Anagram |sort

Here cat is feeding the words in the dictionary to the anagram program. The words are all converted to lower case before feeding by tr. The anagram program will print the signature of each word along with the word onto standard output like this:

aaaabcilllz  calabazilla
aaaabcl  alcaaba
aaaabcllmnrtu  antambulacral


The AWK filter  program prints the words with the same signature on a line.

#!/usr/bin/awk -f
# Shankar Chakkere (shankara_c@yahoo.com)
# Given the input of the form
#    signature word
#
#    prsu  spur
#    prsuu  usurp
#    prsuy  pursy
#    prsuy  pyrus
#    prsuy  syrup
#    prsuyy  syrupy
#   .......
# print all the words which has the same signature
#   pursy pyrus syrup
# which are anagrams.
function saveState(state)
{
 prevSignature = $1;
 prevWord = $2;
 matched = state;
}
{
 if (NR == 1)
 {
 saveState(0);
 }
 else
 {
 # for all the lines greater than 1
 # print the previous word if its signature had matched
 if($1 == prevSignature)
 {
 printf("%s ",prevWord);
 saveState(1);
 }
 else
 {
 # print the previous word if its signature had matched.
 # This is the last word of the anagram list, so print line feed
 if(matched == 1)
 printf("%s\n ",prevWord);
 saveState(0);
 }
 }
}

Tying them all together:

~ Shankar$ cat /usr/share/dict/words |tr [A-Z] [a-z]| ./Anagram |sort |./printAnagram.awk

Will print the list of anagrams on to the standard output.




Labels:


 

Counting Bits

There are many reasons we need to count the number of bits set in a data. It can be used to calculate the parity of a byte. To find the hamming distance etc.There are many ways to do it in C / C++.

Method 1

 

int countBits(unsigned int x)
{
int i=0;
while(x != 0)
{
if(x & 0x1)
{
++i;
}
x >>= 1;
}
return i;
}

How it works?

Unlike the assembly language C or C++ don't have a operator to test if the bit is set. Here we mask the rest of the bits except the least significant bit and test if it is zero or not. It is guaranteed to work for unsigned number because the C++ standard guarantees it.

Shift operators

The value of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has a signed type and a non-negative value, the value of the result is the integral part of the quotient of E1/2E2. If E1 has a signed type and a negative value, the resulting value is implementation-defined.

What it means is , when you shift right, the most significant bit is padded with zero as show in the diagram below.
countBits.jpg

Disadvantage:


For the worst case when least significant and the most significant bits are set eg. 10000001.

Method 2


This method is an exercise in Kernighan and Ritchie's "The C programming Language" book.
int countBits(unsigned int x)
{
int i=0;
while (x != 0)
{
++i;
x &= x - 1; // deletes the rightmost bit that is set in x
}
return i;
}
How it works?

This method uses the property of subtracting a binary number with one. When its done the least significant bit set will be reset.
For decimal 3 which is 011 in binary, the following diagram illustrates the process.
011         value
& 010         value -1     count = 1
------
010

010         value
& 001         value -1     count = 2
------
000
As we see the bit set count is 2.

Advantage:

The number of loops depends on the number of bits set, even for the worst case eg. 10000001 it does it in two loops.

Method 3

Using lookup table. This speeds the operation because we are doing a nibble (4 bits ) at a time instead of a bit at a time.

const int int2bitCount[16] =
{
0,1,1,2,
1,2,2,3,
1,2,3,3,
2,3,4,4
};
int countBits(unsigned int x)
{
int count = 0;
while(x != 0)
{
count += int2bitCount[ x & 0xf ];
x >>= 4;
}
return count;
}

How it works?

The lookup table stores the number of bits that are set for its index. Here we are creating a lookup table for a nibble. 4 bits at a time seems to be a best compromise for space / time. We are also assuming that the integer is a multiple of 4 bits.


Advantage:

The number of loops for the worst case is sizeof( int ) / 4.

This is how you invoke it.

#include <iostream>

int main(int argc, char* argv[])
{
unsigned int x = 0xfffe;
std::cout << std::hex << x << " has " << std::dec << countBits(x) << " bits" << std::endl;
return 0;
}



Labels:


Tuesday, May 13, 2008

 

Creating a binary test file

Some time you need a binary file with known contents to test your communication software.

Here is a quick way to generate one using Gawk. Gawk is GNU AWK.

/cygdrive/c/develop> gawk 'BEGIN {x=0; while(++x<=255){printf "%02x ",x;}; exit}' |xxd -r -p >numtable.bin

Creates a binary file which contains value from 0 to 0xff.

/cygdrive/c/develop> od -t x1 numtable.bin
0000000 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10
0000020 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20
0000040 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30
0000060 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40
0000100 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50
0000120 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60
0000140 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70
0000160 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80
0000200 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90
0000220 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0
0000240 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0
0000260 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0
0000300 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0
0000320 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0
0000340 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0
0000360 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff
0000377

You can extend this to generate a PROM/ROM lookup table like for example a sine table for an 8 bit table.

/cygdrive/c/develop> gawk 'BEGIN {x=0;pi=3.14; while(++x<=90){printf "%02d ",sin(pi/180*x)*100;}; exit}'

Labels:


Saturday, February 10, 2007

 

Encrypting a file.

It is difficult to keep track of all the passwords. I used to write passwords in Kannada ,my language, hoping that not many can read. Now I save all my passwords using KeePass on Windows and KeePassX on Mac OS X. It keeps the entire password in a database and locks it with one master password. The database is compatible across the platform, and the same database can be used on Windows or Mac OS X.

The problem:
Imagine you are on the road, you can't recall the password for a certain web site.
Here is the solution
:
Save a password database as text file and encrypt that file.

Step 1. In keeppass File -> Export To -> CSV File (Under Windows, Or as Text in Mac OS X).
Save it as say Database.kdb.csv. Copy this file onto your thumbdrive.

Step 2. Compiling a multiplatform file encrytion program bcrypt.

In Windows(cygwin):

Download the source and unpack into a directory.
schakkere@shankar ~
$ cd develop/bcrypt/
/ecos-c/usr/shankar/develop/bcrypt

schakkere@shankar ~/develop/bcrypt
$ make
gcc -O2 -Wall -c main.c
gcc -O2 -Wall -c blowfish.c
gcc -O2 -Wall -c rwfile.c
rwfile.c: In function `deletefile':
rwfile.c:123: warning: implicit declaration of function `initstate'
gcc -O2 -Wall -c keys.c
gcc -O2 -Wall -c wrapbf.c
gcc -O2 -Wall -c endian.c
gcc -O2 -Wall -c wrapzl.c
gcc -O2 -Wall -o bcrypt main.o blowfish.o rwfile.o keys.o wrapbf.o endian.o wrapzl.o -L/usr/local/lib -lz
Info: resolving _optind by linking to __imp__optind (auto-import)
Info: resolving _optarg by linking to __imp__optarg (auto-import)

schakkere@shankar ~/develop/bcrypt
$ make install
mkdir -p /usr/local/bin;\
mkdir -p /usr/local/man/man1;\
cp bcrypt /usr/local/bin;\
cp bcrypt.1 /usr/local/man/man1;\
chmod 755 /usr/local/bin/bcrypt;\
chmod 644 /usr/local/man/man1/bcrypt.1

schakkere@shankar ~/develop/bcrypt
$ which bcrypt
/usr/local/bin/bcrypt

schakkere@shankar ~/develop/bcrypt
$ bcrypt
Usage is: bcrypt -[orc][-sN] file1 file2..
-o Write output to standard out
-r Do NOT remove input files after processing
-c Do NOT compress files before encryption
-sN How many times to overwrite input files with random data
To encrypt a file on your thumb drive.
schakkere@shankar ~/develop/bcrypt
$ cd /cygdrive/E/backup/keepass/

schakkere@shankar /cygdrive/E/backup/keepass
$ ls
Database.kdb Database.kdb.csv

schakkere@shankar /cygdrive/E/backup/keepass
$ bcrypt -s5 Database.kdb.csv
Encryption key:Key must be at least 8 characters
Encryption key:
Again:

schakkere@shankar /cygdrive/E/backup/keepass
$ ls -al
drwxr-xr-x 2 schakkere mkgroup-l-d 0 Feb 7 00:21 .
drwxr-xr-x 11 schakkere mkgroup-l-d 0 Feb 7 00:20 ..
-rw-r--r-- 1 schakkere mkgroup-l-d 13084 Jan 10 12:23 Database.kdb
-rw-r--r-- 1 schakkere mkgroup-l-d 2126 Feb 15 22:11 Database.kdb.csv.bfe
Option -s5 overwrites the original file 5 times with random data before deleting it.

Copy bcrypt.exe and cygwin1.dll onto your thumb drive

In Mac OS X:
Unzip the source file.
Shankar-Chakkeres-Computer:~/develop/bcrypt shankar$ make
Copy bcrypt to ~/bin and onto your thumb drive.
You can also run make install if you want it to be available for other users on your system.

Testing it:
Plug the thumbdrive
Shankar-Chakkeres-Computer:~/develop/bcrypt shankar$ ~/bin/bcrypt -r -o /Volumes/6JAN2007/backup/keepass/Database.kdb.csv.bfe | grep -i bank
Encryption key:
"Bank of America","xxx","xxx","xxx","xxx"
It works!

Using it on the road:
Step 3. So now you can use your password on the road even on the machines which does not have bcrypt installed (because you have the executable for Windows and Mac OS X and the encrypted password file on the thumb drive).

Labels: , ,


This page is powered by Blogger. Isn't yours?