Page 1 of 3 123 LastLast
Results 1 to 10 of 27

Thread: Weird problem with real variable

  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
    Delphi has a native SameValue function in Math Unit that I use to compare Float Values.

    Code:
    function SameValue(const A, B: Double; Epsilon: Double): Boolean; 
    begin 
      if Epsilon = 0 then 
        Epsilon := Max(Min(Abs(A), Abs(B)) * DoubleResolution, 
    DoubleResolution); 
      if A > B then 
        Result := (A - B) <= Epsilon 
      else 
        Result := (B - A) <= Epsilon; 
    end;

  8. #8
    Quote Originally Posted by User137 View Post
    You can use Round() instead of Trunc() so 2.7 would round upwards to 3 instead.
    Yep, that's what I did instead. Everything's working now.

    I'm still wondering from a purely computer hardware standpoint why an absolute float value isn't guaranteed. Anybody have some illuminating links on the subject?

  9. #9
    Quote Originally Posted by Christian Knudsen View Post
    Yep, that's what I did instead. Everything's working now.

    I'm still wondering from a purely computer hardware standpoint why an absolute float value isn't guaranteed. Anybody have some illuminating links on the subject?
    It's because in the math world a real number can have an infinite amount of decimals after the dot. However a computer has a finite amount of memory so we can't allow an infinite amount of decimals. It's most common to use 4 or 8 bytes to represent real values called floating points on a computer. Clearly 8 bytes can't provide you with infinite precision so the computer will have to approximate your real number to the closest floating point value it knows how to represent. This is why you can't be guranteed that a real variable holds the exact value you would expect.
    The http://en.wikipedia.org/wiki/IEEE 754 standard describes how floating points are represented in memory.

  10. #10
    Thanks for the reply. I understand why the computer wouldn't be able to hold an infinite amount of decimal points, but when given the simple number of 0.3 with just one decimal, it just seems weird that it's not stored precisely. Why aren't all the decimals following the .3 just zero'ed or something, instead of storing the number as 2.9999999999?

    Reading that Wikipedia link, it seems to me that 0.3 should easily be stored as:

    Code:
    (−1)s ?ó c ?ó bq
    
    s = 1
    c = 3
    b = 10
    q = -1
    Is the issue then that it's base 2 instead of base 10?
    Last edited by Christian Knudsen; 30-12-2010 at 12:19 AM.

Page 1 of 3 123 LastLast

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
  •