#!/bin/bash
function toHTML(){
local inFile=$1;
local outFile="${inFile}.dat";
if [ -f ${outFile} ]; then
rm ${outFile};
fi
sed 's/\t/\ \ \ \ /g' ${inFile} > ${outFile}
sed 's/$/ /g' ${outFile} > tempFile.dat;
mv tempFile.dat ${outFile};
}
fileName="";
if [ $# == 0 ]; then
fileName="\.";
else
fileName=$1;
fi
toHTML ${fileName};
Bits of Learning
Learning sometimes happens in big jumps, but mostly in little tiny steps. I share my baby steps of learning here, mostly on topics around programming, programming languages, software engineering, and computing in general. But occasionally, even on other disciplines of engineering or even science. I mostly learn through examples and doing. And this place is a logbook of my experiences in learning something. You may find several things interesting here: little cute snippets of (hopefully useful) code, a bit of backing theory, and a lot of gyan on how learning can be so much fun.
Friday, June 22, 2012
To Make Your Code Snippet Blogger Ready
Wednesday, June 13, 2012
A Lines of Code Counter
The script below is a simple lines of code counter for you. Following interesting features of the script are:
- It recursively counts the lines of code within all subdirectories of the location mentioned.
- It counts the lines of code of only those files whose extensions are considered as source file name extensions in the list srcFileExtensions defined early in the script.
- Optionally, you could make it exclude the blank lines from the lines of code.
Caution: The script doesn't run like lightning! Suggested optimisations will be gratefully accepted.
Also, there are plenty of superior LOC tools out there. Just google! But for simple plain lines of code counting, this one would still be good for you to begin with. Just copy paste into a bash shell script and go!
Also, there are plenty of superior LOC tools out there. Just google! But for simple plain lines of code counting, this one would still be good for you to begin with. Just copy paste into a bash shell script and go!
#!/bin/bash
FALSE=0;
TRUE=1;
srcFileExtensions=( \
# java # Java
# cpp # C++
# cc # C++
# h # C, C++
# hh # C++
# hpp # C++
# c # C
# py # Python
# pl # Perl
sh # Shell
# flex # flex
# lex # lex
# y # yacc
# yy # yacc
# cs # C#
); # File name extensions which will be considered as source files. Remove/add as needed. Keep the list to minimum to keep the speed good.
function loc_dir(){
local prefix=$1;
if [ ! -d ${prefix} ]; then
echo "${prefix} is not a directory. Quitting...";
exit 1;
fi
local names=( `ls ${prefix}` );
for name in ${names[@]}; do
local fullName=${prefix}/${name};
if [ -d "${fullName}" ]; then
loc_dir "${fullName}"
elif [ -f "${fullName}" ]; then
isSrcFile ${fullName};
local result=$?;
if [ "${result}" == "${TRUE}" ]; then
echo "including ${fullName} ...";
cat "${fullName}" >> "${locFile}";
fi
else
echo "Something wrong with ${fullName}";
fi
done;
}
function remove_empty_lines(){
local prefix=$1;
echo "Removing empty lines...";
local loc="${prefix}/loc.dat";
local loc1="${prefix}/loc1.dat";
mv ${loc} ${loc1};
while read line
do
if [ "${line}" != "" ]; then
echo ${line} >> ${loc};
fi
done <${loc1}
rm ${loc1};
}
function isSrcFile(){
local fileName=$1;
for ext in ${srcFileExtensions[@]}; do
local extLength=`expr length ".${ext}"`;
local nameLength=`expr length "${fileName}"`;
local startPosition=`expr ${nameLength} - ${extLength}`;
local len=`expr ${nameLength} - 1`;
local subString=`echo ${fileName:${startPosition}:${len}}`;
if [ "${subString}" == ".${ext}" ]; then
return ${TRUE};
fi
done;
return ${FALSE};
}
# main
dirname="";
if [ $# == 0 ]; then
dirname="\.";
else
dirname=$1;
fi
locFile="${dirname}/loc.dat";
loc_dir ${dirname};
# remove_empty_lines ${dirname};
if [ -f "${locFile}" ]; then
result=( `wc -l "${locFile}"` );
else
result=0;
fi
loc=${result[0]};
echo "${loc} lines of code."
rm "${locFile}";
Friday, June 11, 2010
About Test-Driven Development
Test-driven development (TDD) refers to the method of software-development where a test case is written prior to implement a feature. Eventually, a working test case also acts as an informal specification of the feature it purports to test.
It's a good practice as it works in a large number of cases. With a unit testing framework (e.g. JUnit, CppUnit, NUnit, ... xUnit) integrated into the development environment, after changing anything, it's particularly convenient to run the whole thing once for a minimal sanity check.
There's a pitfall though, which may result in this method to fall flat. Firstly, one must understand that the possible number of tests one may write is really large for the most trivial application. Consequently, even before the application starts attaining a non-trivial size, the number of test cases may start shooting up at alarming pace. I don't have a first hand experience in employing this method of TDD in a non-trivial development scenario, but my hunch is that maintaining such large test suites written by hand will be by definition a manual process. And that'll be a nightmare for a complex enough software. The problem of doing impact analysis of which changes impact which test case is intractable if tried manually. A small change in the interface may result in a storm of failures resulting from obsolescence of test cases.
I am inclined to think that TDD is an improvement over the largely prevalent method of developing and then writing test cases. TDD gives the developer to go into a tester's mindset interleaved finely with his development exercise. But the improvement is more psychological. It can't be hailed as a technological improvement. In the present scenario where a lot of test generation is manual, that improvement is by no means trivial. But, I feel that TDD will lose its relevance in more formal settings (probably belonging to future) where everything is either statically verified, or the test generation is completely automated from formal specification.
It's a good practice as it works in a large number of cases. With a unit testing framework (e.g. JUnit, CppUnit, NUnit, ... xUnit) integrated into the development environment, after changing anything, it's particularly convenient to run the whole thing once for a minimal sanity check.
There's a pitfall though, which may result in this method to fall flat. Firstly, one must understand that the possible number of tests one may write is really large for the most trivial application. Consequently, even before the application starts attaining a non-trivial size, the number of test cases may start shooting up at alarming pace. I don't have a first hand experience in employing this method of TDD in a non-trivial development scenario, but my hunch is that maintaining such large test suites written by hand will be by definition a manual process. And that'll be a nightmare for a complex enough software. The problem of doing impact analysis of which changes impact which test case is intractable if tried manually. A small change in the interface may result in a storm of failures resulting from obsolescence of test cases.
I am inclined to think that TDD is an improvement over the largely prevalent method of developing and then writing test cases. TDD gives the developer to go into a tester's mindset interleaved finely with his development exercise. But the improvement is more psychological. It can't be hailed as a technological improvement. In the present scenario where a lot of test generation is manual, that improvement is by no means trivial. But, I feel that TDD will lose its relevance in more formal settings (probably belonging to future) where everything is either statically verified, or the test generation is completely automated from formal specification.
Wednesday, December 02, 2009
Code in the blog articles
This is where you could get your code changed into HTML. However, there seem to be many glitches. For one, any debugging has to be one-shot. No incremental debugging will work. The code is generated in one-shot. Hence, any modifications done to the generated code will lost when it's regenerated. Moreover, I can see that it doesn't always render code properly as you would expect. - Wordwrap stops working for the rest of the text on the article. Here, in the current text, I am pressing 'enter' to start a new line. Any suggestions? 1 #include "counter.h" 2 3 Counter::Counter (vector <unsigned int> aBases) 4 : m_Bases (aBases) 5 { 6 for (unsigned int i = 0; i < m_Bases.size (); i++) 7 { 8 m_Count.push_back (0); 9 } 10 } 11 12 void 13 Counter::increment (const unsigned int n) 14 { 15 if (m_Count[n] < (m_Bases[n] - 1)) 16 { 17 m_Count[n]++; 18 } 19 else 20 { 21 m_Count[n] = 0; 22 if (n < m_Bases.size() - 1) 23 { 24 increment (n + 1); 25 } 26 } 27 } 28 29 void 30 Counter::increment () 31 { 32 increment (0); 33 } 34 35 vector <unsigned int> 36 Counter::getCount () 37 { 38 return m_Count; 39 } 40 41 void 42 Counter::print (ostream & fout) 43 { 44 for (unsigned int i = 0; i < m_Count.size (); i++) 45 { 46 fout << m_Count[i] << '\t'; 47 } 48 fout << endl; 49 } 50 51 unsigned int 52 Counter::getNumberOfCounts () 53 { 54 unsigned int Product = 1; 55 for (unsigned int i = 0; i < m_Bases.size (); i++) 56 { 57 Product *= m_Bases[i]; 58 } 59 60 return Product; 61 } 62 63 void 64 Counter::reset () 65 { 66 for (unsigned int i = 0; i < m_Count.size (); i++) 67 { 68 m_Count[i] = 0; 69 } 70 }
Reference:
Using aspell
Here's the aspell command for spell-checking latex file:
aspell --mode=tex --lang=en_GB -c filename
aspell --mode=tex --lang=en_GB -c filename
Wednesday, September 24, 2008
Alien Number System
Here's something about the C++ program I wrote for implementing the alien number system which has an arbitrary set of characters as its digits. Seems to work for all test cases I tried. See Google Codejam sample problems for details:
A number system is represented by a sequence of characters which represent its digits. For example, the decimal number system (also called the base-10 number system) has the characters '0', '1', '2', '3', '4', '5', '6', '7', '8' and '9' as its digits. Representing the number system in this sequence also means the following:
Interface:
That's it!
A number system is represented by a sequence of characters which represent its digits. For example, the decimal number system (also called the base-10 number system) has the characters '0', '1', '2', '3', '4', '5', '6', '7', '8' and '9' as its digits. Representing the number system in this sequence also means the following:
- The first digit (for decimal system, it's '0') is the additive idempotent number. In other words, the effect of adding it to any other number is the same number. In more worldly language, it represents the smallest natural number, or simply, the zero.
- The first number is the multiplicative idempotent number. Which means that by multiplying it to any number, you get back the same number. Also, the difference between any two successive numbers in this number system is this number. In simplest possible terms, its value is one.
- Definition of one gives the definition of the successor function. succ(x) = x + one.
- Addition is repetitive application of the succ function. For instance, in decimal system:
add(3, 4) = succ (succ (succ (succ (3)))) = succ(succ(succ(4))) = succ(succ(5)) = succ(6) = 7.
- Multiplication is a repetitive application of addition function between the number and itself.
multiply(3, 4) = add(3, add(3, add(3, 3))) = add(3, add(6))) = add(3, 9) = 12.
The above phenomena underlie the design of a basic number system. And that's what is done in the code below. Apart from the above, we use some optimisation by implementing the add and multiply functions to simulate the algorithms generally used in manual calculations.Interface:
#ifndef NUMBERSYSTEM_H
#define NUMBERSYSTEM_H
#include <vector>
#include <map>
#include <string>
using namespace std;
class NumberSystem
{
private:
string m_Digits;
map< pair <char, char>, string> m_AddMap;
map< pair <char, char>, string> m_MultiplyMap;
public:
NumberSystem (string);
string add (string, string);
string add (char, char);
string add (string, char);
string multiply (char, char);
string multiply (string, string);
string succ (string);
string prev (string);
string getDigits ();
string getZero ();
char operator[] (unsigned int);
unsigned int size ();
};
string reverse (string);
#endif
Implementation
#include "NumberSystem.h"
NumberSystem::NumberSystem (string aDigits)
: m_Digits (aDigits)
{
// set up a lookup table to to speeden up the addition of two
// single digit numbers. Currently not used anywhere.
for (unsigned int i = 0; i < m_Digits.size (); i++)
{
for (unsigned int j = 0; j < m_Digits.size (); j++)
{
char a = m_Digits[i];
char b = m_Digits[j];
string sum = add (a, b);
pair <char, char> p = pair <char, char>(a, b);
m_AddMap[p] = sum;
}
}
// set up a lookup table to to speeden up the multiplication of two
// single digit numbers. Currently not used anywhere.
for (unsigned int i = 0; i < m_Digits.size (); i++)
{
for (unsigned int j = 0; j < m_Digits.size (); j++)
{
char a = m_Digits[i];
char b = m_Digits[j];
string product = multiply (a, b);
pair <char, char> p = pair <char, char>(a, b);
m_MultiplyMap[p] = product;
}
}
}
// Adds two single digit numbers.
string
NumberSystem::add (char a, char b)
{
string sum(" ");
sum[0] = a;
sum[1] = m_Digits[0];
int j = m_Digits.find (b);
for (unsigned int k = 1; k <= j; k++)
{
sum = succ (sum);
}
return sum;
}
// adds two numbers, one single digit, and another non-single digit.
string
NumberSystem::add (string a, char b)
{
string sum = a;
unsigned int j = m_Digits.find (b);
for (unsigned int k = 1; k <= j; k++)
{
sum = succ (sum);
}
return sum;
}
// adds two non-single digit numbers.
string
NumberSystem::add (string n1, string n2)
{
string a;
string b;
if (n1.size () >= n2.size ())
{
a = n1;
b = n2;
}
else
{
a = n2;
b = n1;
}
string sum;
char carry = m_Digits[0];
for (unsigned int i = 0; i < b.size (); i++)
{
string digitSum = add (a[i], b[i]);
digitSum = add (digitSum, carry);
sum = sum + digitSum[0];
if (digitSum.size () == 2)
{
carry = digitSum[1];
}
else
{
carry = m_Digits[0];
}
}
for (unsigned int i = b.size (); i < a.size (); i++)
{
string digitSum = add (add (a[i], m_Digits[0]), carry);
sum = sum + digitSum[0];
if (digitSum.size () == 2)
{
carry = digitSum[1];
}
else
{
carry = m_Digits[0];
}
}
if (carry != m_Digits[0])
{
sum = sum + carry;
}
return sum;
}
// given any number, it returns the successor of it.
string
NumberSystem::succ (string aNum)
{
if (aNum[0] == m_Digits[m_Digits.size () - 1])
{
aNum[0] = m_Digits[0];
}
else
{
aNum[0] = m_Digits[m_Digits.find (aNum[0]) + 1];
return aNum;
}
for (unsigned int i = 1; i < aNum.size (); i++)
{
if (aNum[i - 1] == m_Digits[0])
{
if (aNum[i] == m_Digits[m_Digits.size () - 1])
{
aNum[i] = m_Digits[0];
}
else
{
aNum[i] = m_Digits[m_Digits.find (aNum[i]) + 1];
return aNum;
}
}
}
if (aNum[aNum.size () - 1] == m_Digits[0])
{
aNum = aNum + m_Digits[1];
}
return aNum;
}
// given any number, this function returns a previous number. Not implemented
// as yet.
string
NumberSystem::prev (string aNum)
{
return aNum;
}
// multiplies two single-digit numbers.
string
NumberSystem::multiply (char aa, char bb)
{
string product (1, m_Digits[0]);
for (string counter (1, m_Digits[0]); counter != string (1, aa); counter = succ (counter))
{
product = add (product, bb);
}
return product;
}
//multiplies two non-single digit numbers.
string
NumberSystem::multiply (string a, string b)
{
vector <string> Products;
for (unsigned int i = 0; i < a.size (); i++)
{
char carry = m_Digits[0];
string product1;
for (unsigned int j = 0; j < i; j++)
{
product1 = product1 + (m_Digits[0]);
}
for (unsigned int j = 0; j < b.size (); j++)
{
string digitProduct = multiply (a[i], b[j]);
digitProduct = add (digitProduct, carry);
product1 = product1 + digitProduct[0];
if (digitProduct.size () == 2)
{
carry = digitProduct[1];
}
else if (digitProduct.size () == 1)
{
carry = m_Digits[0];
}
else
{
exit (1);
}
}
if (carry != m_Digits[0])
{
product1 = product1 + carry;
}
Products.push_back (product1);
}
string product (1, m_Digits[0]);
for (unsigned int i = 0; i < Products.size (); i++)
{
product = add (product, Products[i]);
}
return product;
}
// returns the digits of the number system.
string
NumberSystem::getDigits ()
{
return m_Digits;
}
// returns the zero value of the number system.
string
NumberSystem::getZero ()
{
return string (1, m_Digits[0]);
}
// returns the apos-th digit of the number system
char
NumberSystem::operator [] (unsigned int apos)
{
return m_Digits[apos];
}
// returns the number of digits in the number system.
unsigned int
NumberSystem::size ()
{
return m_Digits.size ();
}
// reverses a string. Used for user-interface purposes.
string reverse (const string s)
{
string o;
if (s.size ())
{
for (unsigned int i = 0; i < s.size (); i++)
{
o = o + s[s.size () - i - 1];
}
}
return o;
}
That's it!
Tuesday, September 23, 2008
Alien Number System
Here's the C++ program I wrote for implementing the alien number system which has an arbitrary set of characters as its digits. Seems to work for all test cases I tried. See Google Codejam sample problems for details:
#include
#include
#include
#include
#include <map>
using namespace std;
string reverse (string);
class NumberSystem
{
private:
string m_Digits;
mapchar, char, string> m_AddMap;
mapchar, char>, string> m_MultiplyMap;
public:
NumberSystem (string);
string add (string, string);
string add (char, char);
string add (string, char);
string multiply (char, char);
string multiply (string, string);
string multiply1 (string, string);
string succ (string);
string prev (string);
string getDigits ();
string getZero ();
char operator[] (unsigned int);
unsigned int size ();
};
NumberSystem::NumberSystem (string aDigits)
: m_Digits (aDigits)
{
for (unsigned int i = 0; i < m_Digits.size (); i++)
{
for (unsigned int j = 0; j < m_Digits.size (); j++)
{
char a = m_Digits[i];
char b = m_Digits[j];
string sum = add (a, b);
pair char, char> p = pair <char, char>(a, b);
m_AddMap[p] = sum;
}
}
for (unsigned int i = 0; i < m_Digits.size (); i++)
{
for (unsigned int j = 0; j < m_Digits.size (); j++)
{
char a = m_Digits[i];
char b = m_Digits[j];
string product = multiply (a, b);
pair <char, char> p = pair <char, char>(a, b);
m_MultiplyMap[p] = product;
}
}
}
string
NumberSystem::add (char a, char b)
{
string sum(" ");
sum[0] = a;
sum[1] = m_Digits[0];
int j = m_Digits.find (b);
for (unsigned int k = 1; k <= j; k++)
{
sum = succ (sum);
}
return sum;
}
string
NumberSystem::add (string a, char b)
{
string sum = a;
unsigned int j = m_Digits.find (b);
for (unsigned int k = 1; k <= j; k++)
{
sum = succ (sum);
}
return sum;
}
string
NumberSystem::add (string n1, string n2)
{
string a;
string b;
if (n1.size () >= n2.size ())
{
a = n1;
b = n2;
}
else
{
a = n2;
b = n1;
}
string sum;
char carry = m_Digits[0];
for (unsigned int i = 0; i < b.size (); i++)
{
string digitSum = add (a[i], b[i]);
digitSum = add (digitSum, carry);
sum = sum + digitSum[0];
if (digitSum.size () == 2)
{
carry = digitSum[1];
}
else
{
carry = m_Digits[0];
}
}
for (unsigned int i = b.size (); i < a.size (); i++)
{
string digitSum = add (add (a[i], m_Digits[0]), carry);
sum = sum + digitSum[0];
if (digitSum.size () == 2)
{
carry = digitSum[1];
}
else
{
carry = m_Digits[0];
}
}
if (carry != m_Digits[0])
{
sum = sum + carry;
}
return sum;
}
string
NumberSystem::succ (string aNum)
{
if (aNum[0] == m_Digits[m_Digits.size () - 1])
{
aNum[0] = m_Digits[0];
}
else
{
aNum[0] = m_Digits[m_Digits.find (aNum[0]) + 1];
return aNum;
}
for (unsigned int i = 1; i < aNum.size (); i++)
{
if (aNum[i - 1] == m_Digits[0])
{
if (aNum[i] == m_Digits[m_Digits.size () - 1])
{
aNum[i] = m_Digits[0];
}
else
{
aNum[i] = m_Digits[m_Digits.find (aNum[i]) + 1];
return aNum;
}
}
}
if (aNum[aNum.size () - 1] == m_Digits[0])
{
aNum = aNum + m_Digits[1];
}
return aNum;
}
string
NumberSystem::prev (string aNum)
{
return aNum;
}
string
NumberSystem::multiply (string a, string b)
{
string counter (1, m_Digits[0]);
string product (1, m_Digits[0]);
for (; counter != b; counter = succ (counter))
{
product = add (product, a);
}
return product;
}
string
NumberSystem::multiply (char aa, char bb)
{
string product (1, m_Digits[0]);
for (string counter (1, m_Digits[0]); counter != string (1, aa); counter = succ (counter))
{
product = add (product, bb);
}
return product;
}
string
NumberSystem::multiply1 (string a, string b)
{
vector Products;
for ( unsigned int i = 0; i < a.size (); i++)
{
char carry = m_Digits[0];
string product1;
for (unsigned int j = 0; j < i; j++)
{
product1 = product1 + (m_Digits[0]);
}
for (unsigned int j = 0; j < b.size (); j++)
{
string digitProduct = multiply (a[i], b[j]);
digitProduct = add (digitProduct, carry);
product1 = product1 + digitProduct[0];
if (digitProduct.size () == 2)
{
carry = digitProduct[1];
}
else if (digitProduct.size () == 1)
{
carry = m_Digits[0];
}
else
{
exit (1);
}
}
if (carry != m_Digits[0])
{
product1 = product1 + carry;
}
Products.push_back (product1);
}
string product (1, m_Digits[0]);
for (unsigned int i = 0; i < Products.size (); i++)
{
product = add (product, Products[i]);
}
return product;
}
string
NumberSystem::getDigits ()
{
return m_Digits;
}
string
NumberSystem::getZero ()
{
return string (1, m_Digits[0]);
}
char
NumberSystem::operator [] (unsigned int apos)
{
return m_Digits[apos];
}
unsigned int
NumberSystem::size ()
{
return m_Digits.size ();
}
string reverse (string s)
{
string o;
if (s.size ())
{
for (unsigned int i = 0; i < s.size (); i++)
{
o = o + s[s.size () - i - 1];
}
}
return o;
}
class Converter
{
private:
string m_Input;
NumberSystem m_Source;
NumberSystem m_Target;
string m_Output;
map string, string> m_Map;
public:
Converter (string, NumberSystem, NumberSystem);
string getOutput ();
string convert ();
void makeMap ();
};
Converter::Converter (string aN, NumberSystem aS, NumberSystem aT)
: m_Input (aN)
, m_Source (aS)
, m_Target (aT)
{
makeMap ();
}
void
Converter::makeMap ()
{
if (m_Source.size () >= m_Target.size ())
{
string cOut = m_Target.getZero ();
for (unsigned int i = 0; i < m_Source.size (); i++)
{
char c[2];
c[0] = m_Source[i];
c[1] = '\0';
m_Map[c] = cOut;
cOut = m_Target.succ (cOut);
}
}
else
{
string cIn = m_Source.getZero ();
for (unsigned int i = 0; i < m_Target.size (); i++)
{
char c[2];
c[0] = m_Target[i];
c[1] = '\0';
m_Map[cIn] = c;
cIn = m_Source.succ (cIn);
}
}
// cout << "*******************************" << endl;
// for (map::iterator I = m_Map.begin (); I != m_Map.end (); I++)
// {
// cout << "Map[" << reverse ((*I).first) << "] = " << reverse ((*I).second) << endl;
// }
// cout << "*******************************" << endl;
}
string
Converter::getOutput ()
{
return m_Output;
}
string
Converter::convert ()
{
string output = m_Target.getZero ();
string nine (1, m_Source[m_Source.size () - 1]);
string ten = m_Target.succ (m_Map[nine]);
for (unsigned int i = 0; i < m_Input.size (); i++)
{
string product = m_Map[string (1, m_Input[i])];
for (unsigned int j = 0; j < i; j++)
{
product = m_Target.multiply (product, ten);
}
output = m_Target.add (output, product);
}
return output;
}
vector;
getInput (istream & fin)
{
unsigned int n;
vector v;
fin >> n;
for ( unsigned int i = 0; i < n; i++)
{
string num;
string s;
string t;
fin >> num;
fin >> s;
fin >> t;
Converter c (reverse (num), s, t);
v.push_back (c);
}
return v;
}
int main (int argc, char ** argv)
{
/*
vector v;
if (argc < 2)
{
cout << "argc = " << argc << endl;
cout << "argv[0] = " << argv[0] << endl;
getInput (cin);
}
else
{
ifstream fin (argv[1]);
v = getInput (fin);
fin.close ();
}
for (unsigned int i = 0; i < v.size (); i++)
{
cout << "output = " << reverse (v[i].convert ()) << endl;
}
*/
/*
Counter c ("01");
for (unsigned int i = 0; i < 100; i++)
{
++c;
cout << reverse (c.getCurrentCount ()) << endl;
}
NumberSystem ns1 ("0123456789");
cout << "45 + 50 = " << reverse (ns1.add (reverse ("45"), reverse ("50"))) << endl;
cout << "4512222 * 50345 = " << reverse (ns1.multiply (reverse ("4512222"), reverse ("50345"))) << endl;
NumberSystem ns2 ("01");
*/
NumberSystem ns1 ("0123456789");
cout << "45113435 * 503112 = " <<>"45113435"), reverse ("503112"))) << endl;
getchar ();
cout << "45113435 * 503112 = " <<>"45113435"), reverse ("503112"))) << endl;
return 0;
}
#include
#include
#include
#include
#include <map>
string reverse (string);
class NumberSystem
{
private:
string m_Digits;
map
map
public:
NumberSystem (string);
string add (string, string);
string add (char, char);
string add (string, char);
string multiply (char, char);
string multiply (string, string);
string multiply1 (string, string);
string succ (string);
string prev (string);
string getDigits ();
string getZero ();
char operator[] (unsigned int);
unsigned int size ();
};
NumberSystem::NumberSystem (string aDigits)
: m_Digits (aDigits)
{
for (unsigned int i = 0; i < m_Digits.size (); i++)
{
for (unsigned int j = 0; j < m_Digits.size (); j++)
{
char a = m_Digits[i];
char b = m_Digits[j];
string sum = add (a, b);
pair char, char> p = pair <char, char>(a, b);
m_AddMap[p] = sum;
}
}
for (unsigned int i = 0; i < m_Digits.size (); i++)
{
for (unsigned int j = 0; j < m_Digits.size (); j++)
{
char a = m_Digits[i];
char b = m_Digits[j];
string product = multiply (a, b);
pair <char, char> p = pair <char, char>(a, b);
m_MultiplyMap[p] = product;
}
}
}
string
NumberSystem::add (char a, char b)
{
string sum(" ");
sum[0] = a;
sum[1] = m_Digits[0];
int j = m_Digits.find (b);
for (unsigned int k = 1; k <= j; k++)
{
sum = succ (sum);
}
return sum;
}
string
NumberSystem::add (string a, char b)
{
string sum = a;
unsigned int j = m_Digits.find (b);
for (unsigned int k = 1; k <= j; k++)
{
sum = succ (sum);
}
return sum;
}
string
NumberSystem::add (string n1, string n2)
{
string a;
string b;
if (n1.size () >= n2.size ())
{
a = n1;
b = n2;
}
else
{
a = n2;
b = n1;
}
string sum;
char carry = m_Digits[0];
for (unsigned int i = 0; i < b.size (); i++)
{
string digitSum = add (a[i], b[i]);
digitSum = add (digitSum, carry);
sum = sum + digitSum[0];
if (digitSum.size () == 2)
{
carry = digitSum[1];
}
else
{
carry = m_Digits[0];
}
}
for (unsigned int i = b.size (); i < a.size (); i++)
{
string digitSum = add (add (a[i], m_Digits[0]), carry);
sum = sum + digitSum[0];
if (digitSum.size () == 2)
{
carry = digitSum[1];
}
else
{
carry = m_Digits[0];
}
}
if (carry != m_Digits[0])
{
sum = sum + carry;
}
return sum;
}
string
NumberSystem::succ (string aNum)
{
if (aNum[0] == m_Digits[m_Digits.size () - 1])
{
aNum[0] = m_Digits[0];
}
else
{
aNum[0] = m_Digits[m_Digits.find (aNum[0]) + 1];
return aNum;
}
for (unsigned int i = 1; i < aNum.size (); i++)
{
if (aNum[i - 1] == m_Digits[0])
{
if (aNum[i] == m_Digits[m_Digits.size () - 1])
{
aNum[i] = m_Digits[0];
}
else
{
aNum[i] = m_Digits[m_Digits.find (aNum[i]) + 1];
return aNum;
}
}
}
if (aNum[aNum.size () - 1] == m_Digits[0])
{
aNum = aNum + m_Digits[1];
}
return aNum;
}
string
NumberSystem::prev (string aNum)
{
return aNum;
}
string
NumberSystem::multiply (string a, string b)
{
string counter (1, m_Digits[0]);
string product (1, m_Digits[0]);
for (; counter != b; counter = succ (counter))
{
product = add (product, a);
}
return product;
}
string
NumberSystem::multiply (char aa, char bb)
{
string product (1, m_Digits[0]);
for (string counter (1, m_Digits[0]); counter != string (1, aa); counter = succ (counter))
{
product = add (product, bb);
}
return product;
}
string
NumberSystem::multiply1 (string a, string b)
{
vector
for (
{
char carry = m_Digits[0];
string product1;
for (unsigned int j = 0; j < i; j++)
{
product1 = product1 + (m_Digits[0]);
}
for (unsigned int j = 0; j < b.size (); j++)
{
string digitProduct = multiply (a[i], b[j]);
digitProduct = add (digitProduct, carry);
product1 = product1 + digitProduct[0];
if (digitProduct.size () == 2)
{
carry = digitProduct[1];
}
else if (digitProduct.size () == 1)
{
carry = m_Digits[0];
}
else
{
exit (1);
}
}
if (carry != m_Digits[0])
{
product1 = product1 + carry;
}
Products.push_back (product1);
}
string product (1, m_Digits[0]);
for (unsigned int i = 0; i < Products.size (); i++)
{
product = add (product, Products[i]);
}
return product;
}
string
NumberSystem::getDigits ()
{
return m_Digits;
}
string
NumberSystem::getZero ()
{
return string (1, m_Digits[0]);
}
char
NumberSystem::operator [] (unsigned int apos)
{
return m_Digits[apos];
}
unsigned int
NumberSystem::size ()
{
return m_Digits.size ();
}
string reverse (string s)
{
string o;
if (s.size ())
{
for (unsigned int i = 0; i < s.size (); i++)
{
o = o + s[s.size () - i - 1];
}
}
return o;
}
class Converter
{
private:
string m_Input;
NumberSystem m_Source;
NumberSystem m_Target;
string m_Output;
map string, string> m_Map;
public:
Converter (string, NumberSystem, NumberSystem);
string getOutput ();
string convert ();
void makeMap ();
};
Converter::Converter (string aN, NumberSystem aS, NumberSystem aT)
: m_Input (aN)
, m_Source (aS)
, m_Target (aT)
{
makeMap ();
}
void
Converter::makeMap ()
{
if (m_Source.size () >= m_Target.size ())
{
string cOut = m_Target.getZero ();
for (unsigned int i = 0; i < m_Source.size (); i++)
{
char c[2];
c[0] = m_Source[i];
c[1] = '\0';
m_Map[c] = cOut;
cOut = m_Target.succ (cOut);
}
}
else
{
string cIn = m_Source.getZero ();
for (unsigned int i = 0; i < m_Target.size (); i++)
{
char c[2];
c[0] = m_Target[i];
c[1] = '\0';
m_Map[cIn] = c;
cIn = m_Source.succ (cIn);
}
}
// cout << "*******************************" << endl;
// for (map
// {
// cout << "Map[" << reverse ((*I).first) << "] = " << reverse ((*I).second) << endl;
// }
// cout << "*******************************" << endl;
string
Converter::getOutput ()
{
return m_Output;
}
string
Converter::convert ()
{
string output = m_Target.getZero ();
string nine (1, m_Source[m_Source.size () - 1]);
string ten = m_Target.succ (m_Map[nine]);
for (unsigned int i = 0; i < m_Input.size (); i++)
{
string product = m_Map[string (1, m_Input[i])];
for (unsigned int j = 0; j < i; j++)
{
product = m_Target.multiply (product, ten);
}
output = m_Target.add (output, product);
}
return output;
}
vector
getInput (istream & fin)
{
vector
fin >> n;
for (
{
string num;
string s;
string t;
fin >> num;
fin >> s;
fin >> t;
Converter c (reverse (num), s, t);
v.push_back (c);
}
return v;
}
int main (int argc, char ** argv)
{
/*
vector
if (argc < 2)
{
cout << "argc = " << argc << endl;
cout << "argv[0] = " << argv[0] << endl;
getInput (cin);
}
else
{
ifstream fin (argv[1]);
v = getInput (fin);
fin.close ();
}
for (unsigned int i = 0; i < v.size (); i++)
{
cout << "output = " << reverse (v[i].convert ()) << endl;
}
*/
Counter c ("01");
for (unsigned int i = 0; i < 100; i++)
{
++c;
cout << reverse (c.getCurrentCount ()) << endl;
}
NumberSystem ns1 ("0123456789");
cout << "45 + 50 = " << reverse (ns1.add (reverse ("45"), reverse ("50"))) << endl;
cout << "4512222 * 50345 = " << reverse (ns1.multiply (reverse ("4512222"), reverse ("50345"))) << endl;
NumberSystem ns2 ("01");
*/
NumberSystem ns1 ("0123456789");
cout << "45113435 * 503112 = " <<>"45113435"), reverse ("503112"))) << endl;
getchar ();
cout << "45113435 * 503112 = " <<>"45113435"), reverse ("503112"))) << endl;
return 0;
}
Friday, November 30, 2007
Operator overloading
Don't overload the ostream & operator <<. Reason: You can't have this operator as a member function of a class (let me know if I am wrong). Therefore, there doesn't seem to be a way for using polymorphism by declaring these operators as virtual.
Class some: A
Class some: B
Class some: C
As you can see above, the objective was to call the operator <<
#include
#include
#include
using namespace std;
class some
{
protected:
string id;
public:
some (string aid){ id = aid; }
friend ostream & operator << (ostream &, some &); virtual ostream & print (ostream & fout)
{
fout "Class some: " <<>return fout;
}
};
class someother : public some
{
public:
someother (string aid) : some (aid){}
virtual ostream & print (ostream & fout)
{
fout << "Class someother: " <<>return fout;
}
};
int main ()
{
some A ("A");
some B ("B");
some * C = new someother ("C");
A.print (cout);
B.print (cout);
(*C)print (cout);
delete C;
return 0;
}
output:
#include
#include
#include
using namespace std;
class some
{
protected:
string id;
public:
some (string aid){ id = aid; }
friend ostream & operator (ostream &, some &);
};
ostream & operator << (ostream & fout, some & asome)
{ fout << "Class some: " << id << endl;}
class someother : public some
{
public:
someother (string aid) : some (aid){}
friend ostream & operator << (ostream &, someother &);
};
ostream & operator << (ostream & fout, someother & asome)
{ fout << "Class someother: " << id << endl;}
int main ()
{
some A ("A");
some B ("B");
some * C = new someother ("C");
cout << style="color: rgb(0, 0, 0);">;
cout << B;
cout << (*C);
delete C;
return 0;
}
Class some: A
Class some: B
Class some: C
As you can see above, the objective was to call the operator <<
#include
#include
#include
class some
{
protected:
string id;
public:
some (string aid){ id = aid; }
friend ostream & operator << (ostream &, some &); virtual ostream & print (ostream & fout)
{
fout "Class some: " <<>return fout;
}
};
class someother : public some
{
public:
someother (string aid) : some (aid){}
virtual ostream & print (ostream & fout)
{
fout << "Class someother: " <<>return fout;
}
};
int main ()
{
some A ("A");
some B ("B");
some * C = new someother ("C");
A.print (cout);
B.print (cout);
(*C)print (cout);
delete C;
return 0;
}
Thursday, August 23, 2007
Classes versus Functions
While working with an OO language like C++ or Java, we often stumble into an issue of choosing between a class and a function.
Let me illustrate the case. Say, we are writing a parser. A C-style way to do is to form it in the shape of a function, say parse (FILE * fin) , that returns the IR after parsing. The caller of this function would be responsible to do what he wants with the IR.
There are more one choice to do the same thing when working with an OO language. A class named Parser would possibly have a parse (FILE * fin) method returning the IR. Or it could have a constructor Parser (string FileName), and an argument-less method parse () returning the IR. The merits of choosing one over the other seem to me rather unimposing. The only difference between the two approaches is that the input for parsing is defined while making a call to the method in the former case, while, in the latter, it gets defined at the time of the creation of the parser object. It hardly matters!
For me, in a basic case, having a parser class is little more than syntactic sugar. May be, in a more advanced scenario, it helps having a class for the Parser, so that parser states can be encapsulated in private attributes. Among these, FileName is surely not one. It can always be passed to the parse method while calling.
I arbitrarily prefer having a parameterised method parse (FILE * File) or parse (string FileName), so that I can use the same parser object for parsing many times. Nothing fundamental about this choice.
Let me illustrate the case. Say, we are writing a parser. A C-style way to do is to form it in the shape of a function, say parse (FILE * fin) , that returns the IR after parsing. The caller of this function would be responsible to do what he wants with the IR.
There are more one choice to do the same thing when working with an OO language. A class named Parser would possibly have a parse (FILE * fin) method returning the IR. Or it could have a constructor Parser (string FileName), and an argument-less method parse () returning the IR. The merits of choosing one over the other seem to me rather unimposing. The only difference between the two approaches is that the input for parsing is defined while making a call to the method in the former case, while, in the latter, it gets defined at the time of the creation of the parser object. It hardly matters!
For me, in a basic case, having a parser class is little more than syntactic sugar. May be, in a more advanced scenario, it helps having a class for the Parser, so that parser states can be encapsulated in private attributes. Among these, FileName is surely not one. It can always be passed to the parse method while calling.
I arbitrarily prefer having a parameterised method parse (FILE * File) or parse (string FileName), so that I can use the same parser object for parsing many times. Nothing fundamental about this choice.
Thursday, June 28, 2007
A Software Engineering Practice Problem
Suppose team A has built a module M, which is used by many of the products of A. Team B borrows M from A. While using it, they find a bug in M. In that process, they also create a fix which works for them. The question is: What should be the process by which the bug is reported to team A, and how should the fix be incorporated?
The potential difficulty is that there are many products that A had made which use M. Hence, if the fix is incorporated in the next version, all those products need to be regression tested.
Of course, it's a very common problem, and people must be doing something to solve it at their own level. Can we note down some common-sense technique here?
The potential difficulty is that there are many products that A had made which use M. Hence, if the fix is incorporated in the next version, all those products need to be regression tested.
Of course, it's a very common problem, and people must be doing something to solve it at their own level. Can we note down some common-sense technique here?
Friday, March 16, 2007
A Small Test Automation System
Here I describe a small test automation system that has come in handy for me. It's very crude and would obviously work for very small scale individual level software development. The kind of software it would work for are those which take an input in the form of a file or from standard input, and output it into the standard output. In particular language translators. However, I am sure that it covers a very broad ground. And a simple constraint of having to build your translator, so it is testable by this kind of testing system will automatically result in good programming practice. I can guarantee that it has yielded some bit of productivity rise for me, a significant increase in correctness as testing and bug catching was easier and hence done more freely, exhaustively and frequently, and hell lot of fun!
We create a directory named test in the directory where the program executable (let's call it prog) is placed. In this directory we create the following directories:
* input : The directory which contains all the inputs of the test cases
* output : The directory where the test harness will dump the outputs of running the prog on each test into a separate file of the same name (possibly with file name extension .out)
* expect : The directory where the expected output of each test case is placed in a separate file of the same name (possibly with file name extension .exp)
* description : The directory where the description of each test case is placed in a separate file of the same name (possibly with file name extension .desc)
We work with the following scripts (written in your favourite scripting language). They are the following:
- createtest : This script asks for a test case name and creates the same. It will look for the input file of the same in the input directory, and will run the prog on it, dumping the output into a file of the same name in the expect directory after getting the user's consent about the correctness of the generated output.
- testTestCase : This script takes as an input a test case name, runs prog on the corresponding input file in input directory, and dumps the output into the output directory. Then it does a simple unix diff between the expected output (the file of the same name in the expect directory), and generated output (the file of the same name in the output directory). It plants the PASS or FAIL verdict into a file (with .log extension) into the current working directory.
- testTestSuite : This script takes as an input the name of a test suite file. The test suite file should contain the names of all the test cases to be tested in the test suite. The testTestSuite runs similar to testTestCase script on all the test cases. It plants its PASS or FAIL verdict for each test case into a file of the same name as the test suite.
createTest.sh
#/bin/sh
testTestCase.sh
#/bin/sh
if [ $# -ne 2 ]
then
echo "Usage - $0 app-name test-case"
exit 1
fi
inputdir="./${1}/input/";
outputdir="./${1}/output/";
expectdir="./${1}/expect/";
CurrentIn="${inputdir}${1}.kc"
CurrentOut="${outputdir}${1}.out"
echo $CurrentIn
echo $CurrentOut
cat $CurrentIn | ../${1} > $CurrentOut
echo "Test result for application ${1} test-case ${2}"
CurrentExpected="${expectdir}${2}.exp"
CurrentOut="${outputdir}${2}.out"
echo "Comparing $CurrentExpected and $CurrentOut"
diff $CurrentExpected $CurrentOut > ${1}.${2}.log
if [ "$?" != "0" ]
then
echo "Test case $2: FAILED!"
else
echo "Test case $2: PASSED!"
fi
testTestSuite.sh
A test suite
1
2
3
4
5
6
7
8
9
10
11
12
19
20
21
22
23
24
25
26
A test verdict:
Test case 1: PASSED!
Test case 2: PASSED!
Test case 3: PASSED!
Test case 4: PASSED!
Test case 5: PASSED!
Test case 6: PASSED!
Test case 7: PASSED!
Test case 8: PASSED!
Test case 9: PASSED!
Test case 10: PASSED!
Test case 11: PASSED!
Test case 12: PASSED!
Test case 19: PASSED!
Test case 20: PASSED!
Test case 21: FAILED!
Test case 22: FAILED!
Test case 23: FAILED!
Test case 24: FAILED!
Test case 25: FAILED!
Test case 26: PASSED!
A download page for this tool (with a more up to date source code and instructions for use)
We create a directory named test in the directory where the program executable (let's call it prog) is placed. In this directory we create the following directories:
* input : The directory which contains all the inputs of the test cases
* output : The directory where the test harness will dump the outputs of running the prog on each test into a separate file of the same name (possibly with file name extension .out)
* expect : The directory where the expected output of each test case is placed in a separate file of the same name (possibly with file name extension .exp)
* description : The directory where the description of each test case is placed in a separate file of the same name (possibly with file name extension .desc)
We work with the following scripts (written in your favourite scripting language). They are the following:
- createtest : This script asks for a test case name and creates the same. It will look for the input file of the same in the input directory, and will run the prog on it, dumping the output into a file of the same name in the expect directory after getting the user's consent about the correctness of the generated output.
- testTestCase : This script takes as an input a test case name, runs prog on the corresponding input file in input directory, and dumps the output into the output directory. Then it does a simple unix diff between the expected output (the file of the same name in the expect directory), and generated output (the file of the same name in the output directory). It plants the PASS or FAIL verdict into a file (with .log extension) into the current working directory.
- testTestSuite : This script takes as an input the name of a test suite file. The test suite file should contain the names of all the test cases to be tested in the test suite. The testTestSuite runs similar to testTestCase script on all the test cases. It plants its PASS or FAIL verdict for each test case into a file of the same name as the test suite.
createTest.sh
#/bin/sh
inputdir="./${1}/input/";
outputdir="./${1}/output/";
expectdir="./${1}/expect/";
descriptiondir="./${1}/description/";
if [ $# -ne 2 ]
then
echo "Usage - $0 app-name test-case"
exit 1
fi
testcasename=$2
ls ${descriptiondir}${testcasename}.desc
if [ "$?" = "0" ]
then
echo "Current Description: `cat ${descriptiondir}${testcasename}.desc`"
echo "Do you want to change the description? (y / n)"
read isNewDesc
if [ "$isNewDesc" = "y" ]
then
`rm ${descriptiondir}${testcasename}.desc`
grep "\/\/" ${inputdir}${testcasename}.kc >> ${descriptiondir}${testcasename}.desc
fi
else
grep "\/\/" ${inputdir}${testcasename}.kc >> ${descriptiondir}${testcasename}.desc
fi
ls ${inputdir}${testcasename}.kc
if [ "$?" = "0" ]
then
echo "Current Input: `cat ${inputdir}${testcasename}.kc`"
echo "do you want to change the input? (y / n)"
read isNewInput
if [ "$isNewInput" = "y" ]
then
`rm ${inputdir}${testcasename}.kc`
unset f
echo "type the test input data (to end the input, type 'eof' in the line following the last input line):"
while :
do
read f
if [ "$f" == eof ]
then
echo "Input data done"
break
fi
echo $f >> ${inputdir}${testcasename}.kc
done
fi
else
unset f
echo "type the test input data (to end the input, type 'eof' in the line following the last input line):"
while :
do
read f
if [ "$f" == eof ]
then
echo "Input data done"
break
fi
echo $f >> ${inputdir}${testcasename}.kc
done
fi
cat ${inputdir}${testcasename}.kc | ../${1} > ${expecteddir}${testcasename}.exp
./viewtest.sh $1 $testcasenam
testTestCase.sh
#/bin/sh
if [ $# -ne 2 ]
then
echo "Usage - $0 app-name test-case"
exit 1
fi
inputdir="./${1}/input/";
outputdir="./${1}/output/";
expectdir="./${1}/expect/";
CurrentIn="${inputdir}${1}.kc"
CurrentOut="${outputdir}${1}.out"
echo $CurrentIn
echo $CurrentOut
cat $CurrentIn | ../${1} > $CurrentOut
echo "Test result for application ${1} test-case ${2}"
CurrentExpected="${expectdir}${2}.exp"
CurrentOut="${outputdir}${2}.out"
echo "Comparing $CurrentExpected and $CurrentOut"
diff $CurrentExpected $CurrentOut > ${1}.${2}.log
if [ "$?" != "0" ]
then
echo "Test case $2: FAILED!"
else
echo "Test case $2: PASSED!"
fi
testTestSuite.sh
#/bin/sh
if [ $# -ne 2 ]
then
echo "Usage - $0 app-name test-suite"
exit 1
fi
inputdir="./${1}/input/";
outputdir="./${1}/output/";
expectdir="./${1}/expect/";
echo "testing application ${1} on test-suite ${2}"
while read f
do
CurrentIn="${inputdir}${f}.kc"
CurrentOut="${outputdir}${f}.out"
echo $CurrentIn
echo $CurrentOut
cat $CurrentIn | ../${1} > $CurrentOut
done < $2
if [ `ls ${2}.log` ]
then
rm ${2}.log
fi
echo "Test result for test-suite ${f}"
while read f
do
CurrentExpected="${expectdir}${f}.exp"
CurrentOut="${outputdir}${f}.out"
echo "Comparing $CurrentExpected and $CurrentOut"
diff $CurrentExpected $CurrentOut > temp
if [ "$?" != "0" ]
then
echo "Test case $f: FAILED!" >> ${1}/${2}.log
else
echo "Test case $f: PASSED!" >> ${1}/${2}.log
fi
done < $2
rm temp
A test suite
1
2
3
4
5
6
7
8
9
10
11
12
19
20
21
22
23
24
25
26
A test verdict:
Test case 1: PASSED!
Test case 2: PASSED!
Test case 3: PASSED!
Test case 4: PASSED!
Test case 5: PASSED!
Test case 6: PASSED!
Test case 7: PASSED!
Test case 8: PASSED!
Test case 9: PASSED!
Test case 10: PASSED!
Test case 11: PASSED!
Test case 12: PASSED!
Test case 19: PASSED!
Test case 20: PASSED!
Test case 21: FAILED!
Test case 22: FAILED!
Test case 23: FAILED!
Test case 24: FAILED!
Test case 25: FAILED!
Test case 26: PASSED!
A download page for this tool (with a more up to date source code and instructions for use)
Subscribe to:
Posts (Atom)