Announcement

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

  • Displaying the local Macro

    Dear Statalists,

    I came across an error when I tried to display a local macro. As you can see in the output below, there is an error when I display local macro X under " " after rounding it to 2 decimal places. Stata displays several fake 0s and one 1. This, however, does not happen when I change to 3 decimal places, display the local macro without " ", or display another local macro Y in the same way. I know the best solution is to round to 3 decimal places, but I'm still curious about why Stata gave me results below.

    I'm using Stata/MP 19.0 (current update level : 07 May 2025)

    Kind regards,
    Yugen

    Code:
    . ** Summarize X
    .
    . su X , meanonly
    
    . di r(mean)
    -92.958839
    
    .
    . * 2 decimal places
    .
    . local X =round(r(mean),0.01)
    
    . di `X'
    -92.96
    
    . di "`X'"
    -92.96000000000001
    
    . * 3 decimal places
    . local X =round(r(mean),0.001)
    
    . di `X'
    -92.959
    
    . di "`X'"
    -92.959
    
    .
    . ** Summarize Y
    .
    . su Y , meanonly
    
    . di r(mean)
    -98.908394
    
    .
    . * 2 decimal places
    .
    . local Y =round(r(mean),0.01)
    
    . di `Y'
    -98.91
    
    . di "`Y'"
    -98.91

  • #2
    after rounding it to 2 decimal places. Stata displays several fake 0s and one 1.
    There is nothing fake about those 0s and 1s. The number -92.96, like most decimal numbers, has no exact finite binary representation (just as 1/3 has no exact finite decimal representation.) The actual closest binary number is going to have a tail like the one you saw. The real question why didn't you see that tail when you ran -di `X'- or when you repeated the exercise with rounding to 3 decimal places.

    The answer to that is that what -di `X'- shows you is a string that -di calculates from the actual internally stored value of `X'. The -display- command is "aware" that in most circumstances when there is a long tail of 0's like the one here, people generally don't want to see that. So -display- has an algorithm that attempts to show what people prefer to see. In this case -di `X'- correctly anticipated what you want. But when you give the command -di "`X'"-, the presence of the quotes somehow led that internal algorithm astray and it showed you more decimal places than you wanted to see. The occurrence of this kind of problem has a random (haphazard is a better word) appearance. The algorithm that -display- uses is somewhat brittle and minor changes in the -display- command can lead to rather different "guesses" as to what the user wants to see. This is pretty understandable considering that the algorithm is, in effect, making an attempt at reading our minds.

    In any case, there is a better way to use -display- to assure that you get to see exactly as many decimal places as you want, no more and no less:
    Code:
    summ X
    display %3.2f `r(mean)' // ALWAYS SHOWS 2 DECIMAL PLACES
    display %4.3f `r(mean)' // ALWAYS SHOWS 3 DECIMAL PLACES
    You can impose any legal Stata display format on the output in this way. By telling -display- what format you want, you save it from having to guess your intentions. It also has the advantage that you don't have to modify the number you are displaying: you can use its original unmodified form, in this case also sparing you the need to resort to creating a macro that serves no other purpose.

    Added: The use of -round()- is probably best restricted to rounding fractional numbers to the nearest integer, which is what you get when no second argument is supplied. -round()-ing to a given number of decimal places produces results that are actually rounding to float or double precision binary of the intended decimal rounding. An approximation to an approximation. This is seldom as useful as it might at first seem.
    Last edited by Clyde Schechter; 16 May 2025, 14:34.

    Comment


    • #3
      Originally posted by Clyde Schechter View Post

      In any case, there is a better way to use -display- to assure that you get to see exactly as many decimal places as you want, no more and no less:
      Code:
      summ X
      display %3.2f `r(mean)' // ALWAYS SHOWS 2 DECIMAL PLACES
      display %4.3f `r(mean)' // ALWAYS SHOWS 3 DECIMAL PLACES
      You can impose any legal Stata display format on the output in this way. By telling -display- what format you want, you save it from having to guess your intentions. It also has the advantage that you don't have to modify the number you are displaying: you can use its original unmodified form, in this case also sparing you the need to resort to creating a macro that serves no other purpose.

      Added: The use of -round()- is probably best restricted to rounding fractional numbers to the nearest integer, which is what you get when no second argument is supplied. -round()-ing to a given number of decimal places produces results that are actually rounding to float or double precision binary of the intended decimal rounding. An approximation to an approximation. This is seldom as useful as it might at first seem.
      Thank you, Professor Schechter, for sharing your insights! I have a follow-up question. What if I'd like to use local macro X somewhere like the plot legend? The legend option looks something like
      Code:
      legend(label(1 "X" "Mean of X = `X'" ) label(2 "Y" "Mean of Y = `Y'" ))
      I guess in this case, I have to use the -round- function.

      Comment


      • #4
        Originally posted by Yugen Chen View Post
        What if I'd like to use local macro X somewhere like the plot legend? . . . I guess in this case, I have to use the -round- function.
        No, you can use the following syntax:
        Code:
        legend(label(1 "X" "Mean of X = `: display %3.2f `X''" ) label(2 "Y" "Mean of Y = `: display %3.2f `Y''" ))

        Comment


        • #5
          Originally posted by Joseph Coveney View Post
          No, you can use the following syntax:
          Code:
          legend(label(1 "X" "Mean of X = `: display %3.2f `X''" ) label(2 "Y" "Mean of Y = `: display %3.2f `Y''" ))
          Brilliant!

          Comment

          Working...
          X