Page 3 of 3 FirstFirst 123
Results 21 to 27 of 27

Thread: Weird problem with real variable

  1. #21
    PGD Staff code_glitch's Avatar
    Join Date
    Oct 2009
    Location
    UK (England, the bigger bit)
    Posts
    933
    Blog Entries
    45
    Hmm. then could you not use an Int64 and multiply by 1000 or 10000 or whatever and just divide it whenever you call a gl(real, pain, here) and then compare them headache free beacuse they are Integers? An Int64 gives plenty of working space. Thats −9,223,372,036,854,775,808 to +9,223,372,036,854,775,807 or any 18 digit number either side the decimal point with 92% of 19 digit numbers covered Tell me if you run wont you?
    I once tried to change the world. But they wouldn't give me the source code. Damned evil cunning.

  2. #22
    Doing the *10 and Round() when comparing the value is fine, since I'm just doing the compare once. And I don't really need the 100% correct float value when passing it in the gl call -- it doesn't really matter there if the number is 0.3 or 0.299999999.
    Laserbrain Studios - Currently developing Hidden Asset!
    Ascii Sector
    - Real-time roguelike in space!

  3. #23
    Yes. Essentially, floating-point fractions are reciprocal multiples of 2: 1/2, 1/4, 1/8, 1/16, etc. There is no combination of any set of those fractions (at least within the range of the type, based on how many bits represent it) which will give you exactly 0.3 (or 0.1, for that matter). They end up dancing all around the value, but never really getting to it.

    In general, however, if you set a float variable to a float constant, like 0.3, it should have the same value as the float constant when compared. I think the difference in this case is the accuracy of the types. Float constants are stored by default in the largest/most accurate type available, which is probably either Double or Extended, and when you compare the values of two different float types, the less precise one is converted to the same type as the more precise one.

    So, for example, if the default float constant type is Double, and you store 0.3 in a Single, it is "truncated" to fit. If you then compare it to the literal float constant 0.3, the Single value is temporarily upconverted back into a Double, then compared. The problem is that there was a loss of information when it was converted to a Single for storage, so the values will not be exact, and the comparison will fail.

    One way to be sure of comparing apples to apples is to value-cast your constants. Like so (assuming the record fields are defined as type Real):

    Code:
    IF (LightSource[I].Radius = Real(1.5)) AND (LightSource[I].R = Real(0.5)) AND (LightSource[I].G = Real(0.5)) AND (LightSource[I].B = Real(0.3)) THEN BEGIN
          Character[CharacterNumber].LightSource := 0;
          LightSource[I].Active := F;
          RemoveLightSourceReferencesOnTiles(I);
          RecalculateTileLighting := T;
       END;
    It's a bit of a pain to change all those casts if you wanted to change it use Singles (for example), and it really only works in this highly-specific situation. In other situations, the epsilon comparison function is more appropriate, and will work fine in this case, too.

    Oh, one other thing, be careful using the Real type, unless you explicitly redeclare it as Single or Double; the actual implementation of it is platform-dependent, so it may cause additional headaches in practice.
    Last edited by Murmandamus; 04-01-2011 at 07:05 PM. Reason: PS

  4. #24
    PGD Community Manager AthenaOfDelphi's Avatar
    Join Date
    Dec 2004
    Location
    South Wales, UK
    Posts
    1,245
    Blog Entries
    2
    I still stand by what I said.... do this....

    Code:
    If (lightsource[i].sourceType=GUNFIRE) then
    begin
      // Do something
    end;
    A single, integer comparison is going to be faster than the sample code. Four floating point comparisons (which as we've discussed are flakey) and the logic to combine their results. I'd go for the single integer comparison any day (in this instance).
    :: AthenaOfDelphi :: My Blog :: My Software ::

  5. #25
    Oh, definitely, if refactoring it to simplify will work, I'd do that, too. I just wanted to explain why floating point can be weird (since the question was asked by the OP), and how to get around / take advantage of the weirdness.

    Knowledge is power.

  6. #26
    PGD Community Manager AthenaOfDelphi's Avatar
    Join Date
    Dec 2004
    Location
    South Wales, UK
    Posts
    1,245
    Blog Entries
    2
    This is true
    :: AthenaOfDelphi :: My Blog :: My Software ::

  7. #27
    Quote Originally Posted by AthenaOfDelphi View Post
    I still stand by what I said.... do this....

    Code:
    If (lightsource[i].sourceType=GUNFIRE) then
    begin
      // Do something
    end;
    A single, integer comparison is going to be faster than the sample code. Four floating point comparisons (which as we've discussed are flakey) and the logic to combine their results. I'd go for the single integer comparison any day (in this instance).
    I might end up doing this if the current code becomes a bottleneck. The code is only called very rarely during runtime, though, (once whenever a weapon has ended firing to check if the light source associated with the character holding the gun should be deactivated -- which probably only happens once every minute or so during play, if that (it's going to be a sneaking/assassination game, not a guns blazing action game)) so I currently prefer to use the existing variables instead of adding new variables that will only be used rarely. Maybe that's just my personal coding preference, or something.
    Laserbrain Studios - Currently developing Hidden Asset!
    Ascii Sector
    - Real-time roguelike in space!

Page 3 of 3 FirstFirst 123

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
  •