rulururu

post Almost Equal Floating Point Numbers

March 25th, 2008

Filed under: C++ — Kai @ 12:25 am

Anyone who’s been writing code for any length of time knows how painful it can be to compare floating point numbers ’cause they’re mere approximations of their true value. For that reason a function to compare floating point values to a specific level of precision is needed.

Don’t understand myself wrong. Usually when comparing floats you round them in a specified way and then compare them.
Here the aim is different: Comparison of the values that were passed and find out if there are almost equal.

Common way with rounding is:

bool CompareFloats(double dVal1, double dVal2, double dTolerance)
{
    return abs(dVal1 - dVal2) < dTolerance;
}

If you wish to have a tolerance of 0.01, then use a constant of some kind. The pow function is also efficient for different levels of decimal precision: pow(0.1, nPrecision);

The following function does comparison of two double values and returns if they’re almost equal. The precision parameter specifies what relative error we are willing to tolerate.

bool AlmostEqualFloats(double dVal1, double dVal2, int iPrecision)
{
	char sVal1[255];
	char sVal2[255];
 
	nPrecision = __max(__min(16, iPrecision), 0);
	sprintf_s(sVal1, sizeof(sVal1), "%.*lf", nPrecision, iVal1);
	sprintf_s(sVal2, sizeof(sVal2), "%.*lf", nPrecision, iVal2);
 
	bool bResult = (strcmp(sVal1, sVal2) == 0);
	return bResult;
}

There’s not much to tell about it. The major disadvantage is the usage of STL’s sprintf_s and strcmp, or better said, the manipulation of strings. Be aware that using strings is somewhat inefficient in a function like that.

Finally, here a version of the function that doesn’t do any string manipulation at all.

bool AlmostEqualFloats(double dVal1, double dVal2, int iPrecision)
{
	iPrecision = __max(__min(16, iPrecision), 0);
	double dTmp = 1.0;
	for (int i = 1; i <= iPrecision; i++)
	{
		dTmp *= 0.1;
	}
	bool bResult = (((nVal2 - dTmp) < nVal1) && (nVal1 < (nVal2 + dTmp)));
	return bResult;
}

When watching this function work in the debugger, you might notice that performing any math of the dTmp value caused it to become impure. The very last digit of the mantissa was some random value. This almost guarantees that at some point, the value will be such that it returns an incorrect result.

To make it clear, here’s a version of the function that accepts a direct value for dTmp in the form of an appropriate value. For instance, if you want a precision of 3, you would pass in 0.001.

bool AlmostEqualFloats(double dVal1, double dVal2, double dTmp)
{
	bool bResult = (((dVal2 - dTmp) < dVal1) && (dVal1 < (dVal2 + dTmp)));
	return bResult;
}

As a conclusion I can say that it is (hardly) impossible to reliably compare two floating point numbers for equality.
Without great performance effort for math calculations can’t write a function that always returns the correct value when comparing floating point numbers. Typically, when people say “almost”, it involves some kind of relativity. For example, 1000000001 is almost 1000000000 and .999999999 is almost 1.

post Interesting way of swapping variables

March 12th, 2008

Filed under: C++ — Kai @ 7:10 am

I found an interesting way of swapping two variables.

Normally I’d just use one of these functions:

void swap(int* i, int* j)
{ 
    int t=*i;
    *i=*j;
    *j=t;
}

or the xor (bitwise) way:

void xorSwap(int* i, int* j)
{
    *i ^= *j;
    *j ^= *i;
    *i ^= *j;
}

Instead of this you also could swap this kinda tricky way:

void swap_vars(int* i, int* j)
{ 
    *j=*i+*j-(*i=*j);
}

For the solution no temporary varbiables are getting used.
It also can be used for any data types and this is more efficient than the normal methods. Additionally it would be thinkable to implement it as a template function.

This little one liner is cute and all, but it is unreadable. So if you use it, you need to add a couple lines of comments saying what it does (not just “swap integers” as that will be assumed to be an out of date comment) which makes the effort of programming greater than using a temp variable.

post string::size_type and unsigned integer

March 11th, 2008

Filed under: C++ — Kai @ 7:26 pm

The C++ std::string class provides string::size_type as an integer datatype large enough to represent any possible string size.

The ‘find’ member function returns the location of the first occurrence of a substring or character in a string. This return value is an integer (whose type is string::size_type). If the substring or character is not found, it needs some value to return that signals this fact.

std::string::size_type std::string::find
                          (char c, std::string::size_type pos ) const;

The maximum value of an int is 2,147,483,647.

Meaning that if a line won’t hold more than 2,147,483,647 characters - which in normal cases never do - then you don’t have to bother declaring string::size_type, you can just declare an integer, which is more simple.

You’d also keep in mind that in theory, you don’t have any knowledge about string::size_type, it could be a 16-bit integer, a 32-bit integer or a 64-bit integer. The only thing a size_type is guaranteed to be is an unsigned integral type.

Even declaring an int for keeping the return value of a function that returns an string::size_type you get a warning because correct thing to do is to always use the string::size_type. That is guaranteed to always work when using C++ STL.

By the way I found this in GCC source code:

#undef SIZE_TYPE
#define SIZE_TYPE "unsigned int"

post An alternative implementation of Trim() for STL

March 5th, 2008

Filed under: C++ — Kai @ 6:00 pm

The C-STL - string.h does provide many functions which are often needed when working with strings.
However, the well-known trim operation is not implemented.

As you probably know is trim or sometimes called strip a common string manipulation function which removes leading and trailing whitespace from a string.

There is no standard trim function in C or C++. Most of the available string libraries for C contain code which implements trimming, or functions that significantly ease an efficient implementation. The function has also often been called EatWhitespace in some, non-standard C libraries.

The open source C++ library Boost has several trim variants. One is:

#include <boost/algorithm/string/trim.hpp>
 
trimmed = boost::algorithm::trim_copy(''string'');

MFC provides a Trim() (which makes problems with VC6) and TrimLeft() / TrimRight() as well.

If you simply need a trim function and not a whole library to be included you can use this.

std::string trim(const std::string& s,const std::string& drop = " ")
{
 std::string::size_type first = s.find_first_not_of( drop );
 std::string::size_type last  = s.find_last_not_of( drop );
 
 if( first == std::string::npos || last == std::string::npos ) return std::string( "" );
   return s.substr( first, last - first + 1 );
}

In addition to string.hI have one more solution for you if you’re being willed using std::string (which doesn’t make much sense in most cases).

Remove whitespaces on the right side:

char* trim_right(char* szSource)
{
  char* pszEOS = 0;
 
  // Set pointer to character before terminating NULL
  pszEOS = szSource + strlen( szSource ) - 1;
 
  // iterate backwards until non ' ' is found
  while( (pszEOS >= szSource) && (*pszEOS == ' ') )
    *pszEOS-- = '\0';
  return szSource;
}

Cut off the left side:

char* trim_left(char* szSource)
{
  char* pszBOS = 0;
 
  pszBOS = szSource;
 
   // iterate backwards until non ' ' is found
   while(*pszBOS == ' ')
    *pszBOS++;
 
  return pszBOS;
}

Trim both sides:

char* trim(char *szSource)
{
  return trim_left( trim_right( trim_left(szSource) ) );
}

You also can use it with std::string when converting the std::string with c_str() method.

Trim function is very useful together with substring.

post I do have namesake that is a compiler

February 22nd, 2008

Filed under: C++, Internet — Kai @ 3:23 pm

When writing the article about performance improvments I originally plant to write a bit more about different compilers and perhaps do create kinda statistics. Finally I didn’t do it ’cause it would have been an overkill for the post.

During preparatory research about different compiler I came by KAI C++ compiler, its name amused me a lot :D

The project-page says:

The powerful features of KAI C++ will make programmers more efficient. The advanced optimizations allow programmers to take full advantage of object-oriented design and software reuse without worrying about performance, because KAI C++ makes objects almost as efficient as hand-coded C. Programmers will spend less time trying to correct performance problems, and instead deliver code that is intuitive and easy to maintain.

Afterwards I tried to collect some information about KAI:

  • According to the copyright (says 1996-1999) the compiler seems to be an older one.
  • Besides the project page and user’s guide it has a website www.kai.com that forwards to Intel website.
  • It’s based on linux standards and owns a manage.
  • It’s not very famous ’cause I wasn’t able to collect as much information as I’d liked to.
  • It’s shareware - donno what a licence costs but they promise you comprehensive and extremely responsive customer support

In conclusion I can say that I’m definitely not interested in KAI C++ compiler. I’m not pretty sure how famous, professional or handy it is, additionally it being shareware makes it totally charmless for me to test it.

post Improve C++ Compile-Time and Run-Time Performance

February 21st, 2008

Filed under: C++ — Kai @ 6:51 pm

Organizing your code as good as possible for great compile time and also, much more important, better run-time performance is still a major point of software development.

An application delivering results faster doesn’t always mean that you’ve to re-design all of the code and does not in any case depend on damn-fast libraries you use. Often things can be made better much easier. In some cases it’s not important what you’re using - even more how you’re using it.

I’d like to show you a number of techniques for improving performance in C++. Non of those “tricks” is a difficult programming trick or something really new. They’re just common things that can make your application a little bit more high-performance.

  • To achieve the fastest build times, compile without debug info and without optimization.
  • GCC parameter -g produces debugging information in the operating system’s native format. You don’t have to produce it every time building your code - it’s just necessary when debugging the project.
    -O3 is often used to generate smaller executables - if you need a small binary you’d use it but when being focused on compile time you’d better use the default -O0.

  • What libraries to use?
  • Most C++ libraries are designed for good performance over a wide range of uses. C++ standard library gives you several good algorithms with a significant number of services. Don’t write every algorithm yourself but sometimes it might happen that the standart C++ library doesn’t provide a perfect solution for your project. Before reproducing an insufficient algorithm have a look at other libraries such as BOOST Library or Apache C++ Standard Library. Especially for painting or threading issues there’s a whole bunch of libraries.

  • Include files
  • Reducing the number of included files by better organisating the project can make compilation more efficient.

    Most programmers add something like this to their headers to avoid including a header more than one time.

    #ifndef MYCLASS_H
      #define MYCLASS_H
      class MyClass 
      { 
       ... 
      };
    #endif

    If the file has not been previously read, the class is defined, otherwise, the file is essentially empty. We can avoid the unnecessary read of the file by testing the guard on the outside of the include as well.

    #ifndef MYCLASS_H
      #include "myclass.h"
    #endif

    This technique is most effective when the compiler is hitting the limits of available main memory and as a result the file cache is ineffective.

  • Usage of inline functions
  • Inline function expansion can significantly increase run time, but the cost is significantly increased compilation time. That means you’d know what has more importance to you - compile time or run time…

    In a previous post I described inlining in detail:
    Inlining - on February 10th, 2008

  • Bit-fields
  • Both C and C++ allow integer members to be stored into memory spaces smaller than the compiler would ordinarily allow.

    Convert boolean and small integer values into bit-fields, and then place these fields adjacent to each other. This technique can substantially reduce data size - this should only be a way if your applications uses too much of memory capacity.

    This can bring benefit to your application when reading external file formats - non-standard file formats for example a 9 bit integers or something like that.

    Mostly bitfields are declared in structures:

    struct A
    {
     unsigned int f1: 4;
     unsigned int f2: 4; 
    };

    It’s more common to use bit fields to store a set of boolean datatype flags compactly. Bit fields are kinda tricky way of space optimization.

  • Converter methods
  • In general you cast an objects that inherits from another into it.
    The usage of dynamic cast is very general, and consequently is more expensive than most specific needs warrant.

    car* pCar = (car*)pVehicle;
    car* cCar = dynamic_cast<car*>( pVehicle );

    You can achieve a lot of useful functionality by providing dynamic converter methods:

    car* pCar = pVehicle->to_car()
     
    class vehicle
    {
        virtual car* to_car() { return (car*)0; }
    };
    class car : vehicle 
    {
        virtual car* to_car() { return this; }
    };

    In most cases this is not just clearer it’s also faster.

  • Default operators
  • Use the default operators. If a class definition does not declare a parameterless constructor, a copy constructor, a copy assignment operator, or a destructor, the compiler will implicitly declare them.

    When the compiler builds a default operator, it knows a great deal about the work that needs to be done and can produce very good code. This code is often much faster than user-written code because the compiler can take advantage of assembly-level facilities.

    Default operators are inline functions, so do not use default operators when inline functions are inappropriate.

  • Passing reference paramters
  • Most programmers, including myself, often pass references to functions ’cause it’s said to faster than a call by value. Sounds logical because for a call be value a copy is needed which allocates storage.

    However, value parameters may be more efficient, and even when they are not directly more efficient, the compiler knows that a value parameter cannot be aliased, and so can better optimize access to the parameter.

  • Temporary objects can be avoided
  • In order to avoid lots of temporary objects which make longer compile time and also reduce performace of the application because more memory is needed you’d consider the following:

    T x = a + b;

    Produces a temporary object for the sum of a and b and the passes it into x of class T.

    T x(a); x += b;

    Above solution doesn’t need a temporary object.

  • Write member variables into local variables
  • Accessing member variables is a common operation in C++ member functions.
    Due the fact that you need to read/write members the compiler must often load member variables from memory through the this pointer.

    This pointer might not always be valid which forces the application to reload the member every time again whenever it’s needed. If you pass your member at the top of a function into a local variable it’s just accessed one time and in the rest of the function the local varible can be used.

    That way you can avoid unnecessary memory reloads.

    Another great advantage that improves performace is that the values can reside in registers, as is the case with primitive types.

  • Too many function calls
  • You often see things like that:

    if(App->MyClass->GetInstance())
    {
    App->MyClass->GetInstance()->GetAll()->Select(...);
    MyClass->GetInstance()->GetAll()->SelectTop();
    }

    You don’t have to do that. Often this is a result of copy and paste lines as everybody does lots of times.

    Nevertheless a more readable and also cached memory reducing solution is:

    MyClass* inst = App->MyClass->GetInstance();
    if(inst)
    {
    inst->GetAll()->Select(...);
    inst->GetAll()->SelectTop();
    }
  • const does not improve run performace
  • Many programmers use const reference parameters for functions with the intent to inform the compiler that the parameter is read-only. The const keyword says that the storage may not be modified through the given name.

    What it does not say is that the storage cannot be modified through some other name. Only variables directly declared as const are really constant.

    Basically it’s an ineffective way for improving run-time performance. It does, however, catch errors in the programming process.

  • Deallocating memory
  • Once unnecessary allocations are eliminated, the next most effective technique for improving performance is to deallocate memory when it is no longer needed. This is best accomplished with explicit calls to delete.

    However, applications may lose control of their memory, and a conservative garbage collector can sometimes be a critical tool. The C++ compiler provides a conservative garbage collector with the option -library=gc.

  • Loop optimizations
  • The most simple thing to remove some spare loops which can simply be written outright. Consider this:

    for(int i=0; i<4; i++) 
    array[i] = i;

    this is logically the same as

    array[0] = 0; 
    array[1] = 1, 
    array[2] = 2; 
    array[3] = 3;

    Of course it’s nonsense doing this in on or two parts of your projects. But if you have thirty or more of those parts it might give you back some performance.

    Do as less checking in a loop as possible, try just giving the filtered data objects, those that really should be passed through, to a loop.

  • Different compiler versions
  • It’s interesting to know that GCC 2.95.3 does faster compile code than version 3 compilers.
    This shouldn’t be the determining factor ’cause using the newest (or a newer) version of GCC is always recommented. A downgrade to a lower version can just be necessary because of an application getting no longer compiled by the newer one.

Delay optimization as much as possible, and don’t do it if you can avoid it. Optimizing too early or too often is not a good approach to engineering. Better to have a program that runs than a fast program that crashes. Better rethink your concept twice before starting the programming work instead of correting half of the project afterwards.

ruldrurd
« Previous PageNext Page »
Powered by WordPress, Content and Design by Kai Bellmann
Entries (RSS) and Comments (RSS)