Announcement

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

  • Issue with rounding off decimals

    I am trying to use multiples of .05 saved in a series of local macros, and I only want two decimal places (not display format, but the content itself). Then I find this issue:

    local num1 = 12*.05
    local num2 = 14*.05
    local sr1 = round(12*.05, .01)
    local sr2 = round(14*.05, .01)

    macro dir


    . macro dir
    ...
    _sr2: .7000000000000001
    _sr1: .6
    _num2: .7000000000000001
    _num1: .6000000000000001



    It seems that the round() function can deal with .6000000000000001 correctly, but not .7000000000000001. Is this a bug?
    Is there another working method to get exact two-decimal numbers?

  • #2
    there has been lots of discussion of this issue on Statalist; use search to find these discussions, but also see
    Code:
    help precision

    Comment


    • #3
      I think locals in Stata are basically strings. Scalars are numbers. E.g.
      Code:
      . dis 14*.05
      .7
      
      . dis round(14*.05,.01)
      .7
      
      . local s1 = 14*.05
      
      . dis "`s1'"
      .7000000000000001
      
      . local s2 = round(14*.05,.01)
      
      . dis "`s2'"
      .7000000000000001
      Who knows what the round() function does on strings...

      Comment


      • #4
        I agree with Rich that precision is at the root of this problem.

        Given that, perhaps you are just looking to prepare macros to be used as strings, perhaps in text you are displaying, for example. In that case perhaps this example will be helpful.
        Code:
        . local num1 = 12*.05
        
        . local num2 = 14*.05
        
        . local sr1 = round(12*.05, .01)
        
        . local sr2 = round(14*.05, .01)
        
        . local tr1 : display %9.2f 12*.05
        
        . local tr2 : display %9.2f 14*.05
        
        . 
        . macro list _num1 _sr1 _tr1 _num2 _sr2 _tr2
        _num1:          .6000000000000001
        _sr1:           .6
        _tr1:            0.60
        _num2:          .7000000000000001
        _sr2:           .7000000000000001
        _tr2:            0.70

        Comment


        • #5
          Originally posted by William Lisowski View Post
          I agree with Rich that precision is at the root of this problem.

          Given that, perhaps you are just looking to prepare macros to be used as strings, perhaps in text you are displaying, for example. In that case perhaps this example will be helpful.
          Code:
          . local num1 = 12*.05
          
          . local num2 = 14*.05
          
          . local sr1 = round(12*.05, .01)
          
          . local sr2 = round(14*.05, .01)
          
          . local tr1 : display %9.2f 12*.05
          
          . local tr2 : display %9.2f 14*.05
          
          .
          . macro list _num1 _sr1 _tr1 _num2 _sr2 _tr2
          _num1: .6000000000000001
          _sr1: .6
          _tr1: 0.60
          _num2: .7000000000000001
          _sr2: .7000000000000001
          _tr2: 0.70
          Thanks for the solution. This will work.

          Comment


          • #6
            Originally posted by Rich Goldstein View Post
            there has been lots of discussion of this issue on Statalist; use search to find these discussions, but also see
            Code:
            help precision
            Thanks. I kind of get that this might be a precision issue now. I guess 12*.05 and 14*.05 are on the edges of whether being treated as the same as 0.6 or 0.7. It is still unfortunate that the round() function does not do the trick of trimming off the tails.

            Comment


            • #7
              "Unfortunate" is the wrong word when the implication is that Stata should be able to solve an insoluble problem.

              This question or one similar has been asked hundreds of times on Statalist, and that is not surprising because the issue mixes together

              * what people want to see versus what Stata can hold in memory

              * differences between integers and numbers with fractional parts

              * differences between numbers and strings

              * the fact that computers (almost always) work in binary at machine level, not decimal.

              Back in 1964 or so the last point was the burden of my first lesson about computing.. It is a point that most people on Statalist should know but much effort goes into hiding the fact from Stata users -- and even Stata programmers. Sometimes it appears suddenly out of the darkness to bite users.

              If I have 7.000001 and want to round to the nearest integer this is a soluble problem with which Stata has no difficulty -- because 7 is an integer that can be found, stored exactly in binary and displayed, and the difference between the number 7 and the string "7" is also easy to understand.

              If I have 0.7000001 and want to round to one decimal place, this is a different and difficult problem which Stata can only solve indirectly -- because 0.7 is a decimal with no exact binary representation. So, an exact equivalent of 0.7 in binary does not exist as a number that can be stored and displayed. But you can ask to see numbers presented to 1 decimal place (or in general a specified number of decimal places) and that is soluble as a problem in calculating and presenting strings.

              Other software may appear to solve this problem, but other software will just be dividing the roles differently
              Last edited by Nick Cox; 30 Jul 2020, 03:33.

              Comment


              • #8
                Nick, all that you are saying is very interesting and new to me. However you are saying that 0.7 number does not exist in the machine binary way of thinking, and yet the -round()- claims to be able to deliver 0.7, then it fails to deliver 0.7. Is that not a problem?

                Comment


                • #9
                  The language seems contentious here. In what sense is round() claiming to do what you say?

                  For example, round() with second argument 0.5, 0.25, 0.125 or any other (small negative) power of two should perform as expected

                  round() with second argument 0.1, 0.01, 0.001 and so forth will often surprise if people don't think hard enough about what they are asking, It's ultimately impossible for code to catch when users are misunderstanding what code can do -- as misunderstanding. Sometimes a misunderstanding will be caught as a syntax error.

                  A real question is how well this is documented.

                  * The help for the function doesn't go that far and that could be disappointing. It's not StataCorp style to add warnings in function help and that could disappoint, but that's between a user and StataCorp. For example, it's only tacit in help for logarithm functions that zero or negative arguments will yield missings. No doubt, some users would appreciate more detail on why missing is the result there. (And an advanced user with experience elsewhere might expect Stata to yield a complex number as the logarithm of a negative argument.) If anyone has a suggestion for revising documentation for round(), send it in to StataCorp. I've often done something similar over the years.

                  * There is much documentation beyond the help of this general issue, usually under the heading of "precision", and it would be fair comment that you do need to know where to look for it. But people who've encountered this issue before can flag discussions they know or give explanations (Rich Goldstein, #2; William Lisowski, #4) and in that sense Statalist works as well as can be expected.

                  Comment

                  Working...
                  X