Thread: Genetic Random Number Guessing Agent (GRNGA)

  1. #1
    Registered User
    Join Date
    Jan 2004
    Posts
    10

    Unhappy Genetic Random Number Guessing Agent (GRNGA)

    No, its not as fancy as the title suggested. It doesn't even work yet, which is why I posted here.

    What it does: It is an introduction to programming Genetic AI for myself. It is supposed to take in a number from the user, and then 'evolve' a way to add 5 numbers that will result in the given number.

    How it does it: A class 'Chromosome' contains 5, in the beginning, randomly generated numbers and a fitness rating based on how close to the target number the sum of those 5 numbers are.
    I start out with a 'population' of 100 Chromosomes, among which the 50 Chromosomes closest to the target are singled out and allowed to 'mate'. They are then put together in pairs and in those pairs combine their numbers into new chromosomes. The old chromosomes are then deleted and the new ones become the new generation. This continues until a chromosome has come up with a correct solution.

    Why it doesn't do it: My worst nightmare, Segmentation fault...
    I spent 4 hours yesterday trying to figure out the reason for this.
    I haven't got a clue as to what could be causing it... Any help is greatly appreciated.

    If something in the description was too fuzzy (I came directly from working on a Fuzzy Logic AI ) just ask!
    Last edited by Keybone; 05-27-2004 at 01:23 AM.
    #include "Sig.h"
    #ifndef noob
    #define noob keybone
    #endif

  2. #2
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    >My worst nightmare, Segmentation fault...
    Segmentation faults are caused by dereferencing wild pointers. That's the case you should be looking for. A good idea is to trace your program testing for null pointers and low addresses as well as compiler assigned "invalid but easily recognizable" addresses like 0xcdcdcdcd or 0xfeefee.
    My best code is written with the delete key.

  3. #3
    Registered User
    Join Date
    Jan 2003
    Posts
    311
    You have a large number of off by one errors in your for loops. if a has five elements then only a[0]...a[4] are well defined. Here in the mid-ninties we solved such problems with std::vector.

  4. #4
    Normal vector Carlos's Avatar
    Join Date
    Sep 2001
    Location
    Budapest
    Posts
    463
    Quote Originally Posted by Prelude
    >A good idea is to trace your program testing for null pointers and low addresses as well as compiler assigned "invalid but easily recognizable" addresses like 0xcdcdcdcd or 0xfeefee.
    1.) Testing for NULL pointers doesn't bring too much if you don't set them to NULL after deletion.
    In case of allocation problems, the (C++) standard says that operator new must throw an exception of type bad_alloc instead of returning NULL pointer in case of allocation problems, however MS VisualC++ still acts in the later way (it's not a standard behaviour!).
    Keybone, if you're not using MS VisualC++, you should place try / catch( bad_alloc& ) pairs where new operator is called, for VC++ checking for NULL pointers will do it.

    I'm not concerned you get segmentation faults because of dereferencing invalid pointers - this causes rather access violations.

    2.) Prelude, which compiler uses 0xfeefee as memory-marker?
    MS VisualC++ surely not.

    Here the values used by MS VisualC++ compiler in debug builds:
    - 0xCC - local uninitialized variables get this value
    - 0xFD - NoMansLand marker; for bytes on either sides of the memory reserved for your application data
    - 0xDD - freed heap bytes are marked with this value
    - 0xCD - uninitialized objects filled with this value

    Have a nice code!

  5. #5
    Normal vector Carlos's Avatar
    Join Date
    Sep 2001
    Location
    Budapest
    Posts
    463
    > for(int i=0;i<5;i++)
    > GenerationsNeeded++
    1.) Just a hint - there's no reason to use post-increment operator, as far you don't use the temporary returned. It should be:
    Code:
     for(int i=0;i<5;++i)
    ...
    ++GenerationsNeeded;
    2.) instead of numerical constants, rather use (MACRO) constants to define upper / lower bounds.

    3.) You are passing parameters by value - very bad practice. You should pass them by reference to avoid construction/destruction of temporaries

    > Chromosome operator +(Chromosome otherparent)
    should be
    Code:
    Chromosome operator + ( const Chromosome& otherparent )
    4.) Much vorse, operator = returns void instead of reference to this. And again, parameter passing...
    > void operator =(Chromosome equality)

    I'm stopping now, you should inspect a good C++ book than revise your code.

  6. #6
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    >Here in the mid-ninties we solved such problems with std::vector.
    std::vector doesn't perform range checking by default. You have to use the v.at(i) member function in place of the subscript operator.

    >1.) Testing for NULL pointers doesn't bring too much if you don't set them to NULL after deletion.
    I don't recall mentioning anything about deletion. I also didn't look at the code because I tend not to download attachments. My suggestions were merely a starting point for debugging a segmentation violation.

    >I'm not concerned you get segmentation faults because of dereferencing invalid pointers - this causes rather access violations.
    In this case the two are the same. An out of range subscript is dereferencing an invalid address, thus causing a segmentation fault which is called an access violation on your compiler. The error is the same though, the program has accessed a location outside of its address space.

    >2.) Prelude, which compiler uses 0xfeefee as memory-marker?
    I'm not familiar with every C++ compiler in existence, I was merely giving examples of recognizable pattern based addresses.

    >MS VisualC++ surely not.
    Not everyone uses MS VisualC++

    >1.) Just a hint - there's no reason to use post-increment operator, as far you don't use the temporary returned.
    For stylistic purposes such as consistency with object incrementing, it couldn't hurt. But if you're trying to suggest that preincrement in this situation would be more efficient then you're wrong. Only the most simple-minded compiler wouldn't implement an optimization that makes the two equivalent. Even the first C compiler did so.

    >rather use (MACRO) constants to define upper / lower bounds.
    Define MACRO. If you mean preprocessor definitions OR const qualified integers OR enumerations then I have no problem. If you mean only preprocessor definitions then you're a bit behind the times. Good C++ style recommends against using the preprocessor whenever you can manage it.
    My best code is written with the delete key.

  7. #7
    &TH of undefined behavior Fordy's Avatar
    Join Date
    Aug 2001
    Posts
    5,793
    >>Testing for NULL pointers doesn't bring too much if you don't set them to NULL after deletion.
    In case of allocation problems, the (C++) standard says that operator new must throw an exception of type bad_alloc instead of returning NULL pointer in case of allocation problems, however MS VisualC++ still acts in the later way (it's not a standard behaviour!).

    Depend on the version of VC++. If you are using VC++.Net then it will throw an exception. If you are using VC++6 or before (created before the standards were finalised) then the compiler is to old for you to get that exception thrown

  8. #8
    Normal vector Carlos's Avatar
    Join Date
    Sep 2001
    Location
    Budapest
    Posts
    463
    > I don't recall mentioning anything about deletion.
    Me neither, just listed the cases when checking for NULL pointers would have sense. When you delete and set it to NULL, then OK, check for NULL. Else it has no reason, unless you use MS VC++ - and, as you said "Not everyone uses MS VisualC++ ".


    >2.) Prelude, which compiler uses 0xfeefee as memory-marker?
    I'm not familiar with every C++ compiler in existence, I was merely giving examples of recognizable pattern based addresses.

    ...wich 0xfeefee is surely not. These patterns should be byte-patterns.

    > But if you're trying to suggest that preincrement in this situation would be more efficient then you're wrong.

    Nope. It's about bad style and habits.

    > If you mean only preprocessor definitions then you're a bit behind the times.
    I meant of course OR - hope everybody knows that macro constants lack of type checking...

    Again, I didn't meant to offend you or question your skills, just have another opinion in this issue. Hope it doesn't hurt

  9. #9
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    >When you delete and set it to NULL, then OK, check for NULL. Else it has no reason, unless you use MS VC++
    Clearly you know better, but as I read it, you seem to think that a pointer can only be set to null after calling delete on a pointer to heap allocated memory, and then only if the code does so explicitly. There are many more cases where a pointer can be set to null, not the least of which being explicit initialization (which you should know of and use since you keep talking about good style ):
    Code:
    T *p = 0;
    Ruling out a potential case is never a good idea, especially when a null pointer is a commonly used return value denoting failure and a commonly used initialization value for pointers that won't be used immediately.

    >...wich 0xfeefee is surely not. These patterns should be byte-patterns.
    As you wish, but with all due respect, you completely missed the point.

    >Nope. It's about bad style and habits.
    Style is subjective. Too many people express their opinions as fact, even I do occasionally.

    >I meant of course OR
    That's what I thought. I was just forcing you to be more clear.

    >Hope it doesn't hurt
    Why would it hurt?

    I'll note one more time that I haven't even looked at the OP's code. I was giving suggestions for debugging a segmentation fault/access violation error.
    My best code is written with the delete key.

  10. #10
    Registered User
    Join Date
    May 2003
    Posts
    82
    Quote Originally Posted by Prelude
    Code:
    T *p = 0;
    Speaking of style, is there a difference between these two?
    Code:
    T* ptr = 0;
    T* ptr2 = NULL;

  11. #11
    Sweet
    Join Date
    Aug 2002
    Location
    Tucson, Arizona
    Posts
    1,820
    yes NULL is ((void*)0) and zero is well zero
    Woop?

  12. #12
    Registered User
    Join Date
    Jan 2004
    Posts
    10
    Quote Originally Posted by Carlos
    > for(int i=0;i<5;i++)
    > GenerationsNeeded++
    1.) Just a hint - there's no reason to use post-increment operator, as far you don't use the temporary returned. It should be:
    Code:
     for(int i=0;i<5;++i)
    ...
    ++GenerationsNeeded;
    Well, its just me being used to using post-increment operators. I'll keep that in mind though if i need help with something from here.

    Quote Originally Posted by Carlos
    2.) instead of numerical constants, rather use (MACRO) constants to define upper / lower bounds.
    Do you mean like declaring a "const int uBound=5"? As that boundary changes with almost every for-loop, i'd much rather have numerical constants on site than a looong list of constants.

    Quote Originally Posted by Carlos
    3.) You are passing parameters by value - very bad practice. You should pass them by reference to avoid construction/destruction of temporaries

    > Chromosome operator +(Chromosome otherparent)
    should be
    Code:
    Chromosome operator + ( const Chromosome& otherparent )
    Ok, I'll fix that but could this cause any errors?

    Quote Originally Posted by Carlos
    4.) Much vorse, operator = returns void instead of reference to this. And again, parameter passing...
    > void operator =(Chromosome equality)
    Is it possible to have
    Code:
    Chromosome a,b,c;
    a = b = c;
    and it is the reason for having = return a reference to an object?

    Quote Originally Posted by Carlos
    I'm stopping now, you should inspect a good C++ book than revise your code.
    I've gone through 6 books used by the swedish school with a magnifying glass, granted that they were less-than-good at times... Can you recommend any books?

    Quote Originally Posted by Carlos
    Keybone, if you're not using MS VisualC++, you should place try / catch( bad_alloc& ) pairs where new operator is called, for VC++ checking for NULL pointers will do it.
    I am using DJGPP, so I'll try that.There are no explicit new's in the source but Im guessing I should try/catch where I create the Population array like below?
    Code:
    int main()
    {
    	srand(time(NULL));
    	try{
                               Chromosome Population[101];
                    }
                    catch(bad_alloc)
                    {
                               cerr << "Bad Allocation";
                               exit(1);
                    }
    ...
    The source has been edited in the first post.
    Last edited by Keybone; 05-27-2004 at 01:36 AM.
    #include "Sig.h"
    #ifndef noob
    #define noob keybone
    #endif

  13. #13
    Normal vector Carlos's Avatar
    Join Date
    Sep 2001
    Location
    Budapest
    Posts
    463
    Do you mean like declaring a "const int uBound=5"? As that boundary changes with almost every for-loop, i'd much rather have numerical constants on site than a looong list of constants.

    I've found at least two for loops with upper bound set to 5. Furthermore, you most probably need such a constnat, in case you iterate through a given array in more functions / code blocks.

    it possible to have
    Code:
    Chromosome a,b,c;
    a = b = c;
    and it is the reason for having = return a reference to an object?
    Else why sould you declare operator = ?? That's the point.

    I am using DJGPP, so I'll try that.There are no explicit new's in the source but Im guessing I should try/catch where I create the Population array like below?
    The exception will bethrown only by operator new. Furthermore I don't think that's an allocation problem, rather off-by-one errors, as grib has mentioned. Sorry, havent' tried your source.

    Two *great* book I could recommend: Scott Meyers' "Effective C++" and "More effective C++". Both treat practical issues that ground-up C++ books and of course reference books do not mention at all.

    Have fun!

  14. #14
    Registered User
    Join Date
    Jan 2004
    Posts
    10
    Oh, I see now.
    Anyway, I've changed it now, just have to test with the changes.
    I'll see if I can get hold of those books, then. Thanks!
    Last edited by Keybone; 05-27-2004 at 02:32 AM.
    #include "Sig.h"
    #ifndef noob
    #define noob keybone
    #endif

  15. #15
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    Quote Originally Posted by AH_Tze
    Speaking of style, is there a difference between these two?
    Code:
    T* ptr = 0;
    T* ptr2 = NULL;
    It depends on how NULL is defined. Because C++ requires a cast to convert between void * and other pointer types, the latter assignment could potentially be an error if NULL is defined as:
    Code:
    #define NULL ((void *)0)
    However, the chances of that being the case are slim with current compilers as an unadorned 0 in pointer context is almost always treated correctly as a null pointer. As such, NULL is usually defined as:
    Code:
    #define NULL 0
    It's a matter of opinion concerning which of the two assignments you showed are better style, so use whichever you feel more comfortable with.
    My best code is written with the delete key.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. random number problems
    By lespaul5895 in forum C Programming
    Replies: 3
    Last Post: 07-05-2007, 02:16 AM
  2. Random number + guessing game trouble
    By Ravens'sWrath in forum C Programming
    Replies: 16
    Last Post: 05-08-2007, 03:33 AM
  3. Generating a random number?
    By Konspiracy in forum C++ Programming
    Replies: 5
    Last Post: 04-28-2007, 12:33 AM
  4. How do I restart a random number sequence.
    By jeffski in forum C Programming
    Replies: 6
    Last Post: 05-29-2003, 02:40 PM
  5. random number
    By mrukok in forum C++ Programming
    Replies: 7
    Last Post: 03-16-2003, 08:04 PM