Announcement

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

  • Double precision problem

    Dear all

    I am using comparisons with variables in double precision and the problem is that extracting cell values to local macros changes precision. Here is an illustration of the problem:

    Code:
    clear
    set obs 1
    gen double a = 2093.1234567891899
    local A=a in 1
    assert `A'>a
    noi di %20.18g `A'
    noi di %20.18g a
    The command assert should report an error, but it does not, because the value of `A' is different from the value of variable (this changes if one replaces the last digit of the number of line three by a digit below 5). For float variables I would use
    Code:
    assert float(`A')>float(a)
    , but there does not seem to be an equivalent function for double precision, such as
    Code:
     assert double(`A')>double(a)
    .
    Any help appreciated.
    Last edited by Christian Thöni; 04 Mar 2024, 08:03.

  • #2
    If you display using the %21x format:

    Code:
     di %21x `A'
    +1.05a3f35ba7015X+00b
    
    . di %21x a
    +1.05a3f35ba7014X+00b
    you can see that the internal representations differ in the last bit, suggesting Stata uses different rounding conventions in the two cases. See

    https://blog.stata.com/2012/04/02/th...sion/#section5.

    I have no suggestions, sorry.

    Comment


    • #3
      The local macro can at best hold a string version of a decimal representation of what is held in your variable in binary. Nothing is changed; your variable A is exactly as you defined it, to the best of Stata's ability; it's just that the local macro isn't guaranteed to do exactly what you want. The keyword here is precision.

      Incidentally

      Code:
      local a = A in 1
      shouldn't even work but in 1 is seemingly ignored by Stata as trailing garbage.

      Code:
      local a = A[1]
      is closer in spirit but as it happens the result is the same.

      As what you've done is loosely similar to putting something in a box, and then trying to check that it's there as you put it in, what is the real problem here?

      Scalars hold more precision than locals, if that helps.

      Comment


      • #4
        Originally posted by Christian Thöni View Post
        but there does not seem to be an equivalent function for double precision, such as
        Code:
         assert double(`A')>double(a)
        .
        That is because there does not need to be. The equivalent is

        Code:
        assert `A' > a
        By default, Stata compares in double (and sometimes calculates in quad-) precision.

        It should be obvious that Stata cannot magically increase precision after the fact. Once precision is lost by using local macros, not scalars, there is no way of getting back the precision.

        Possible solutions (without details about the underlying problem) have been suggested:

        Code:
        scalar A = a[1]
        or

        Code:
        local A : display %21x a[1]
        will preserve double precision.
        Last edited by daniel klein; 04 Mar 2024, 09:54.

        Comment


        • #5
          Thank you for your answers. The use of scalars instead of locals and the "display %21x" version do solve the problem.

          BTW: I think "local A=a in #" and "local A=a[#]" are equivalent.
          Last edited by Christian Thöni; 04 Mar 2024, 09:54.

          Comment


          • #6
            You evidently do think that but nothing documented about local
            macros shows support of if or in qualifiers.

            Experiment shows that at best such qualifiers are ignored, not understood.
            Last edited by Nick Cox; 04 Mar 2024, 10:05.

            Comment


            • #7
              Code:
              sysuse auto, clear
              list price in 1/3
              local p=price in 3
              di `p'

              Comment


              • #8
                You're correct. My best line here is that this wasn't allowed that I can recall in earlier versions of Stata. If that's wrong, then I am just wrong. Sorry about that.

                It is still a little risky to rely on something not documented.

                Comment


                • #9
                  According to syntax diagram

                  Code:
                  local lmname =exp in #
                  should not be allowed.

                  I think this is a bug as becomes more obvious in this example:

                  Code:
                  . sysuse auto
                  (1978 automobile data)
                  
                  . local x = price in 1/3
                  
                  . display `x'
                  4099
                  I do not believe that anyone could have predicted this outcome based on what is documented.
                  Last edited by daniel klein; 04 Mar 2024, 10:32. Reason: displayed the wrong local macro

                  Comment


                  • #10
                    The syntax with a range of observations still works, just returns the first hit.
                    Code:
                    sysuse auto, clear
                    list price in 1/3
                    local p=price in 2/3
                    di `p'
                    I think this can be handy. I would even appreciate if Stata would allow for something like

                    Code:
                    sysuse auto, clear
                    list price in 1/3
                    local p=price if  foreign==1
                    which would return the first value found for which the condition is satisfied.

                    Comment


                    • #11
                      Originally posted by Christian Thöni View Post
                      The syntax with a range of observations still works, just returns the first hit.
                      You could argue that this really is the worst-case scenario for software: return a seemingly valid result for invalid (undocumented) input and not even do so consistently.

                      Edit:

                      OK, you could make the case that

                      Code:
                      local lmname = varname
                      is equivalent to

                      Code:
                      local lmname = varname in 1/L
                      or, more generally

                      Code:
                      local lmname = varname in #/#
                      which always returns the first observation. However, it should be documented that local accepts in ranges then.
                      Last edited by daniel klein; 04 Mar 2024, 10:49.

                      Comment

                      Working...
                      X