Results 1 to 10 of 27

Thread: Weird problem with real variable

Hybrid View

Previous Post Previous Post   Next Post Next Post
  1. #1

    Weird problem with real variable

    Sorry about the vague topic title, but I have no idea what's going on here and was therefor not able to give a more precise topic title. Anyway...

    I'm programming in FreePascal 2.2.2 on Win32 and have run into a strange issue with a real variable. I have a procedure called PlaceLightsource like this:

    Code:
    PROCEDURE PlaceLightSource(Const LightSourceNumber : Byte; Const Radius, HotSpot, X, Y, Red, Green, Blue : Real; Const Life : SmallInt);
    BEGIN
       LightSource[LightSourceNumber].AbsoluteX := X;
       LightSource[LightSourceNumber].AbsoluteY := Y;
       LightSource[LightSourceNumber].Active := T;
       LightSource[LightSourceNumber].HotSpot := HotSpot;
       LightSource[LightSourceNumber].Life := Life;
       LightSource[LightSourceNumber].Radius := Radius;
       LightSource[LightSourceNumber].R := Red;
       LightSource[LightSourceNumber].G := Green;
       LightSource[LightSourceNumber].B := Blue;
       PlaceLightSourceReferencesOnTiles(LightSourceNumber);
       RecalculateTileLighting := T;
    END;
    I then call this procedure like this:

    Code:
       PlaceLightSource(I, 1.5, 0, X, Y, 0.5, 0.5, 0.3, -1);
    So, LightSource[I].Radius should now be set to 1.5, LightSource[I].R to 0.5, LightSource[I].G to 0.5, and LightSource[I].B to 0.3. If I get the program to print the values of these variables to the screen, it checks out fine.

    However, when I call this piece of code...

    Code:
       IF (LightSource[I].Radius = 1.5) AND (LightSource[I].R = 0.5) AND (LightSource[I].G = 0.5) AND (LightSource[I].B = 0.3) THEN BEGIN
          Character[CharacterNumber].LightSource := 0;
          LightSource[I].Active := F;
          RemoveLightSourceReferencesOnTiles(I);
          RecalculateTileLighting := T;
       END;
    ...it never gets past the IF check. Weird. Even more weird, if I comment out the "AND (LightSource[I].B = 0.3)", it does everything it's supposed to do. So I double checked that LightSource[I].B = 0.3 by printing the value to the screen again, and it IS 0.3. Now, if I set it to 0.5, it also works fine!

    I'm completely stumped by this. Is anybody aware of some things to look out for when checking the value of real variables?

  2. #2
    Try to avoiding this kind of check. Because 0.3 can be not exactly 0.3. It can be 0.30000000001 or 0.29999999999.
    So you can check like this: if round(b*10)=3 (dont like it) or like this: > 0.29 and < 0.31 (for example).
    Theory is - when you know everything but nothing works.
    Practice is - when all works, but you don't know why.
    We combine theory and practice - nothing works and nobody knows why

  3. #3
    Make a special equals() function, like this:

    Code:
    const
      //A treshold for float comparison
      EPSILON = 1e-5;
    
    implementation
    
    function Equals(const a, b: Single): Boolean;
    begin
      Result := (a - b < EPSILON);
    end;
    Make similar functions to compare vectors and colors.
    Coders rule nr 1: Face ur bugz.. dont cage them with code, kill'em with ur cursor.

  4. #4
    Small changes, cause you forgot function call ABS(a - b)

    Code:
    const
      //A treshold for float comparison
      EPSILON = 1e-5;
    
    implementation
    
    function Equals(const a, b: Single): Boolean;
    begin
      Result := (abs(a - b) < EPSILON);
    end;
    Thomas

  5. #5
    Interesting! And thanks for the replies!

    So, when you assign the value 0.3 to a real, you can't be 100% sure that it actually gets the precise value? That seems a bit odd.


    EDIT: Still doesn't work. I tried this:
    Code:
       IF (Trunc(LightSource[I].Radius * 10) = 15) AND (Trunc(LightSource[I].R * 10) = 5)
       AND (Trunc(LightSource[I].G * 10) = 5) AND (Trunc(LightSource[I].B * 10) = 3) THEN BEGIN
          Character[CharacterNumber].LightSource := 0;
          LightSource[I].Active := F;
          RemoveLightSourceReferencesOnTiles(I);
          RecalculateTileLighting := T;
       END;
    And it will still only go into the IF block if I comment out the "AND (Trunc(LightSource[I].B * 10) = 3)" bit.


    ANOTHER EDIT: It seems that Trunc(LightSource[I].B * 10) returns 2, so 0.3 must actually be something just below 0.3, like 0.299999999999, or something...
    Last edited by Christian Knudsen; 29-12-2010 at 05:59 PM.

  6. #6
    You can use Round() instead of Trunc() so 2.7 would round upwards to 3 instead.

  7. #7
    Quote Originally Posted by KidPaddle View Post
    Small changes, cause you forgot function call ABS(a - b)

    Code:
    const
      //A treshold for float comparison
      EPSILON = 1e-5;
    
    implementation
    
    function Equals(const a, b: Single): Boolean;
    begin
      Result := (abs(a - b) < EPSILON);
    end;
    Thomas
    Argh.. that's indeed a stupid mistake. Thanks for the heads up.
    Coders rule nr 1: Face ur bugz.. dont cage them with code, kill'em with ur cursor.

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •