Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • if qualifier does not work with decimals

    Dear Statalist users,

    I have come across something I do not quite understand: why does the if qualifier work for integer values of a vriable, but not if the values are decimals?
    See the following example (I have Stata 12 SE):

    sysuse auto
    * 1.
    gen myvar1=0
    replace myvar1=1 if turn==40
    * This works fine: 6 real changes made

    * 2.
    replace turn = turn/100
    gen myvar2=0
    replace myvar2=1 if turn==0.40
    * This does not: 0 real changes made

    * 3.
    replace myvar2=1 if turn>0.39999999 & turn<.40000001
    * This again works: 6 real changes made

    Why does the second example not work? And is there a nicer workaround than what I did in the third example?
    Looking forward to your comments!

    Isabel



  • #2
    This is a precision issue. There is no way to represent 0.40 (base 10) exactly in base 2. See http://blog.stata.com/2012/04/02/the...-to-precision/ for a full explanation.

    Depending on the genesis of your variables and the degree of tolerance that is workable in your context, the following workaround might be successful:

    Code:
    replace myvar2 = 1 if float(turn) == float(0.40)

    Comment


    • #3
      Hi,

      Clyde is right: it's all about precision. As -turn- is float, you encounter rounding issues when dividing it by 100.
      As an alternative to Clyde's solution, you could also -recast- the original variable to be double precision before your operation, and it works fine:
      Code:
      . sysuse auto , clear
      (1978 Automobile Data)
      . recast double turn
      . replace turn = turn/100
      (74 real changes made)
      . gen myvar2=0
      . replace myvar2=1 if turn==0.40
      (6 real changes made)
      Regards
      Bela

      Comment


      • #4
        I'll add that the display format is also relevant. In the example below, xy appears to have a value of 2.2 in the data browser and if you list it. Using the if qualifier with floating-point types is not something I recommend. If you know that all values are precise to the first decimal place, then you can use round().

        Code:
        . clear
        
        . set obs 1
        obs was 0, now 1
        
        . gen x = 1.1
        
        . gen double y = 1.1
        
        . gen double xy = x + y
        
        . list
        
             +-----------------+
             |   x     y    xy |
             |-----------------|
          1. | 1.1   1.1   2.2 |
             +-----------------+
        
        . count if x == 1.1
            0
        
        . count if x == float(1.1)
            1
        
        . count if xy == 2.2
            0
        
        . count if xy == float(2.2)
            0
        
        . count if round(x,.1) == 1.1
            1
        
        . count if round(xy,.1) == 2.2
            1

        Comment


        • #5
          Dear Clyde, Daniel, and Robert,

          Thank you for your replies, they clarified my question.

          Comment

          Working...
          X