No announcement yet.

Error in STR$ ?

  • Filter
  • Time
  • Show
Clear All
new posts

  • Error in STR$ ?

    In searching some solutions to a problem in a scientific journal I wrote the
    following basic programme and hit some problems with STR$. Please run the code
    to see for yourself - I commented the problems (errors???) in the code:

    'error in STR$()?
    'the code: find 'a' for a^b for which a=sum(digits a^b)
    DEFLNG a-z
    FOR b = 8 TO 9 'exponent (here 8-9 as too many solutions with lower exp.)
    FOR a = 2 TO 99 'base number
    g&& = a^b 'number
    IF g&& < 0 THEN EXIT FOR 'number was bigger than max Quad: 2^63-1
    g$ = STR$(g&&,18) 'number as digits with 18 digs precision (STR$ defaults to 16, max is 18)
    L = LEN(g$) 'length is digits in the number
    s = 0 'intiation for sum of separate digits
    FOR i = 1 TO L
    s = s + VAL(MID$(g$,i,1)) 'sum of separate digits in the number
    NEXT i
    IF s = a THEN MSGBOX "a="+STR$(a)+", b="+STR$(b)+", number="+g$
    NEXT b
    NEXT a
    MSGBOX "all found" 'but not 8^63, 9^71 and 9^81
    'if g$ = STR$(g&&) is used instead of STR$(g&&,18) then 8^63 is found, but 54^9 is not

    p! = 28/9 'this is 3.111111
    MSGBOX STR$(p!,18) 'STR$ erroneously adds some other digits


    It seems correct that 9^81 can not be displayed by STR$ because with the sign it has 19 digits.

    I did find a way to correctly display all solutions as follows:
    instead of the line "g$ = STR$(g&&,18)" replace it by:

    g1&& = g&& \ 1000000000 : g2&& = g&& - g1&&*1000000000 'split large numbers in 2
    IF g1&& THEN
    g$ = STR$(g1&&) + LTRIM$(STR$(g2&&)) 'LTRIM$ is used to delete the leading (+) sign
    g$ = STR$(g&&) 'number smaller than 1000000000
    END IF

    I do not understand the strange behaviour of STR$ and would like to get some explanation.
    Maybe this is another something to fix for PB R&D? Also, it would make sense to accomodate
    STR$ for the longest possible number in the next PBDLL release.

    Thanks, Jules


  • #2
    Jules --
    > p! = 28/9 ' this is 3.111111

    It's not so. Convert 28/9 to IEEE-format manually. Then make reverse operation (to decimal).

    All other problems... Probably I lost something, but I understood nothing.
    Why do you talk about errors in STR$ ?
    First of all, it's necessary to imagine exactly, how PB executes ^ and converts data types.

    E-MAIL: [email protected]


    • #3

      I guess I was too brief in my message, but I wanted to keep it short...
      When I wrote "p!=28/9 'this is 3.111111", I meant thats what it is in single precision, otherwise you can just continue to add as many 1's as you like.
      The problem as indicated by running my program is that you actually get STR$(p!,18)=3.111111640930176, which is really incorrect!

      Further, I did make the mistake in exchanging a and b (eg. it should be 81^9 and not 9^81) in the examples, but I don't think it matters how PB executes ^ powers because this part is identical/unchanged for all types of STR$ that I indicated/used. I actually also checked all largest numbers (this is really up to the limit of QUAD - 19 digits) and several smaller ones and they are all correctly calculated.
      Fact is that STR$(g&&,18) 'forgets' to find 63^8 and 71^9 while STR$(g&&) does find 63^8, but now 'forgets' 54^9 (here 71^9 can not be displayed by STR$ because it contains 17 digits + the sign).
      When I use the solution (for STR$) by splitting the number in two parts, then all numbers are correctly found/displayed. Because g&& is always calculated the same way, I think it really is the strange behaviour of STR$ that is in question, not the calculation itself!!!

      Still waiting for the explanation...
      Thanks, Jules



      • #4
        There is no error in STR$(). The STR$() function is a floating point function which also happens to work with whole, non-fractional numbers, when they are in range.

        The limit of precision of STR$() is a mantissa of up to 18 decimal digits. Like all floating point operations, when the limit of mantissa is exceeded, the data is rounded. That's precisely why it is defined as floating point, rather than some other representation.


        Bob Zale
        PowerBASIC Inc.



        • #5
          Jules --
          Following sample illustarates, what does STR (in my understanding).
             #Compile Exe
             #Register None
             #Dim All
             Function PbMain
                Dim s As Single, sh As String * 32   , ss As Ext
                s = 28 / 9
                ReDim ss(0 To 0) As Long At VarPtr(s)
                sh = Bin$(ss(0), 32)
                MsgBox "Internal representation:" + $CRLF + _
                       "Sign (0 means +, 1 means -) : " + Left$(sh, 1) + _
                       "    Exponent (+127) : " + Mid$(sh, 2, 8) + " (binary)" + _
                       "    Mantissa : 1." + Mid$(sh, 10, 23) + " (binary)"
                      '  0 10000000 10001110001110001110010
                 MsgBox  "Calculate using Calc: " + Str$(&B10001110001110001110010) + "; divide" + Str$(2^23) + _
                         "; add 1 (mantissa is ready); multiply" + Str$(2 ^ (&B10000000 - 127))
             End Function
          If you will calculate in Calc, you will receive these "wrong" figuges.
          I know that VB, for example, will show 3.111111. Well, if there is a wish, it possible to use Format or STR$(Round(s, 6)).

          E-MAIL: [email protected]


          • #6
            Thanks Bob and Semen,

            The knowledge of many people of this forum is just great!
            I understand now why different 'STR$ precisions' might turn up different results
            and that is exactly why hopefully in the next PBDLL release I hope to see an improved STR$
            or other format to at least correctly and fully display all different types of numbers...
            If we can't use 'PRINT a' anymore to display any number, it seems logical that there should be another
            straightforward way to do this with the expected behaviour, eg. keeping the correct precision of the
            variable [unless explicitely requested otherwise like with the STR$(var,x)].

            Many thanks again, Jules



            • #7
              I've been following this thread, and I still have a question...

              It seems that STR$() does not give 18 digit accuracy with extended precision
              as stated on page 326 of the PB/DLL 6 users' guide. The following example
              shows what I mean. Except for extended precision, STR$() works as I would expect.

              #COMPILE EXE
              #DIM ALL
              FUNCTION PBMAIN
                 LOCAL u1 AS SINGLE, u2 AS DOUBLE, u3 AS EXT, u AS EXT
                 u1 = 28/9
                 u2 = 28/9
                 u3 = 28/9
                 u = 2.0 / 3.0
                 MSGBOX STR$(u1, 18) + $CRLF + STR$(u2,18) + $CRLF + STR$(u3,18)_
                        + $CRLF + STR$(u, 18)
              END FUNCTION



              • #8
                If you want a specific precision when doing maths on numeric literals, then you must make sure you 'cast' your numeric literals to the desired precision, or the compiler will choose the lowest precision the value will fit (this behavior is documented).
                u1 = 28!/9!
                u2 = 28#/9#
                u3 = 28##/9##

                PowerBASIC Support
                mailto:[email protected][email protected]</A>
                mailto:[email protected]


                • #9
                  Lance, I thought so too. I tried it casting the literals just as you suggested,
                  but I got the same thing. And wanting to keep the example just like p.326, I
                  left off the casting. And wouldn't the RHS casting be automatic anyway, so as to
                  match the LHS variable declarations?



                  • #10
                    No, PowerBASIC has always automatically cast based upon the literals absolute value, not the context of the expression. As I noted, this behavior is described in the documentation.

                    BTW, I'm not at my DEV PC to run these tests for you, but you will not get 80-bit precision unless you switch the FPU into 80-bit precision mode first. Switching the FPU into 80-bit precision mode is shown in a message in the FAQ Forum.

                    BTW #2, this exact topic was discussed in a parallel thread in the last week or so, and may make worth while reading.

                    PowerBASIC Support
                    mailto:[email protected][email protected]</A>
                    mailto:[email protected]