Author Topic: Scientific or exponential notation remover  (Read 324 times)

Offline bplus

  • Forum Resident
  • Posts: 5300
  • B+ Knot again!
Scientific or exponential notation remover
« on: September 04, 2020, 07:51:14 PM »
I am testing last function in Steve's Math Evaluator and ran into a curiosity for n = 1 in default Single.

The 0's jump 1 extra 0 between 7 and 8, all other numbers I've tested seem OK

Code: QB64: [Select]
  1. _TITLE "N2S$ testing for a scientific notation remover" 'b+ 2020-09-04
  2.  
  3. ' looks pretty good except for one little bug
  4.  
  5. IF 1 THEN ' < 0 to skip section, 1 to run section
  6.     n = 1 ' has an odd bug jump -7 to -8 moves right 1 extra 0
  7.     FOR i = 0 TO 20
  8.         PRINT i, N2S$(STR$(n * 10 ^ -i));
  9.         LOCATE CSRLIN, 54: PRINT N2S$(STR$(n * 10 ^ i))
  10.     NEXT
  11.  
  12. IF 0 THEN '  < 0 to skip section, 1 to run section
  13.     n## = 1 ' but this OK too
  14.     'n## = 27.0123456789 'OK
  15.     'n## = (1 / 3) 'OK
  16.     FOR i = 0 TO 20
  17.         PRINT i, N2S$(STR$(n## * 10 ^ -i));
  18.         LOCATE CSRLIN, 54: PRINT N2S$(STR$(n## * 10 ^ i))
  19.     NEXT
  20.  
  21. FUNCTION N2S$ (EXP$) 'remove scientific Notation to String (~40 LOC)
  22.     'SMcNeill Jan 7, 2020 ref: https://www.qb64.org/forum/index.php?topic=1555.msg112989#msg112989
  23.     'Last Function in code marked Best Answer (removed debug comments and blank lines added these 2 lines.)
  24.     t$ = LTRIM$(RTRIM$(EXP$))
  25.     IF LEFT$(t$, 1) = "-" OR LEFT$(t$, 1) = "N" THEN sign$ = "-": t$ = MID$(t$, 2)
  26.     dp = INSTR(t$, "D+"): dm = INSTR(t$, "D-")
  27.     ep = INSTR(t$, "E+"): em = INSTR(t$, "E-")
  28.     check1 = SGN(dp) + SGN(dm) + SGN(ep) + SGN(em)
  29.     IF check1 < 1 OR check1 > 1 THEN N2S = EXP$: EXIT SUB 'If no scientic notation is found, or if we find more than 1 type, it's not SN!
  30.     SELECT CASE l 'l now tells us where the SN starts at.
  31.         CASE IS < dp: l = dp
  32.         CASE IS < dm: l = dm
  33.         CASE IS < ep: l = ep
  34.         CASE IS < em: l = em
  35.     END SELECT
  36.     l$ = LEFT$(t$, l - 1) 'The left of the SN
  37.     r$ = MID$(t$, l + 1): r&& = VAL(r$) 'The right of the SN, turned into a workable long
  38.     IF INSTR(l$, ".") THEN 'Location of the decimal, if any
  39.         IF r&& > 0 THEN
  40.             r&& = r&& - LEN(l$) + 2
  41.         ELSE
  42.             r&& = r&& + 1
  43.         END IF
  44.         l$ = LEFT$(l$, 1) + MID$(l$, 3)
  45.     END IF
  46.     SELECT CASE r&&
  47.         CASE 0 'what the heck? We solved it already?
  48.             'l$ = l$
  49.         CASE IS < 0
  50.             FOR i = 1 TO -r&&
  51.                 l$ = "0" + l$
  52.             NEXT
  53.             l$ = "0." + l$
  54.         CASE ELSE
  55.             FOR i = 1 TO r&&
  56.                 l$ = l$ + "0"
  57.             NEXT
  58.             l$ = l$
  59.     END SELECT
  60.     N2S$ = sign$ + l$
  61.  
  62.  
  63.  

@SMcNeill  a puzzle for you.

I don't think this will stop me from using it, as is, though getting this curiosity explained or fixed would be nice :)

« Last Edit: September 04, 2020, 07:52:51 PM by bplus »

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 2782
    • Steve’s QB64 Archive Forum
Re: Scientific or exponential notation remover
« Reply #1 on: September 04, 2020, 08:01:25 PM »
I’ll dig into it in a few days.  Today and Tomorrow, I’m down watching over my mom (she’s dealing with early onset Alzheimer's), so it’ll probably be Sunday by the earliest, before I can sort out what’s going on.  ;) 
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 2782
    • Steve’s QB64 Archive Forum
Re: Scientific or exponential notation remover
« Reply #2 on: September 06, 2020, 04:31:52 PM »
Good catch!  Negative notation isn't something which we see very often, and the glitch here is mine, instead of QB64s.

1e-8 -- this says we have 1, then shift it to the right 8 places, giving us 0.00000001...

Unfortunately, I simply interpeted it as "add 8 zeros in front", giving us 0.000000001...  This is an extra 0, which we don't actually have!

(In my defense, 1e8 is as simple as "add 8 zeros behind", giving us 100000000...  Unfortunately, the same logic doesn't quite hold true, in this case, for negative exponents.)

The change is extremely simple to implement:

Down on line 52, change the following:             FOR i = 1 TO -r&&

To:              FOR i = 1 TO (-r&& - 1)

That's it!  One little alteration and it works as it should.  This glitch is entirely from my own flawed logic with notations, and has nothing at all to do with QB64.   

1e-1 = 0.1, not .01, as I was thinking it did.

Fixed code is below, for those who simply don't want to alter it themselves:

Code: QB64: [Select]
  1. _TITLE "N2S$ testing for a scientific notation remover" 'b+ 2020-09-04
  2.  
  3. ' looks pretty good except for one little bug
  4.  
  5. IF 1 THEN ' < 0 to skip section, 1 to run section
  6.     n = 1 ' has an odd bug jump -7 to -8 moves right 1 extra 0
  7.     FOR i = 0 TO 20
  8.         PRINT i, N2S$(STR$(n * 10 ^ -i));
  9.         LOCATE CSRLIN, 50: PRINT N2S$(STR$(n * 10 ^ i))
  10.     NEXT
  11.  
  12. IF 0 THEN '  < 0 to skip section, 1 to run section
  13.     n## = 1 ' but this OK too
  14.     'n## = 27.0123456789 'OK
  15.     'n## = (1 / 3) 'OK
  16.     FOR i = 0 TO 20
  17.         PRINT i, N2S$(STR$(n## * 10 ^ -i));
  18.         LOCATE CSRLIN, 54: PRINT N2S$(STR$(n## * 10 ^ i))
  19.     NEXT
  20.  
  21. FUNCTION N2S$ (EXP$) 'remove scientific Notation to String (~40 LOC)
  22.     'SMcNeill Jan 7, 2020 ref: https://www.qb64.org/forum/index.php?topic=1555.msg112989#msg112989
  23.     'Last Function in code marked Best Answer (removed debug comments and blank lines added these 2 lines.)
  24.     t$ = LTRIM$(RTRIM$(EXP$))
  25.     IF LEFT$(t$, 1) = "-" OR LEFT$(t$, 1) = "N" THEN sign$ = "-": t$ = MID$(t$, 2)
  26.     dp = INSTR(t$, "D+"): dm = INSTR(t$, "D-")
  27.     ep = INSTR(t$, "E+"): em = INSTR(t$, "E-")
  28.     check1 = SGN(dp) + SGN(dm) + SGN(ep) + SGN(em)
  29.     IF check1 < 1 OR check1 > 1 THEN N2S = EXP$: EXIT SUB 'If no scientic notation is found, or if we find more than 1 type, it's not SN!
  30.     SELECT CASE l 'l now tells us where the SN starts at.
  31.         CASE IS < dp: l = dp
  32.         CASE IS < dm: l = dm
  33.         CASE IS < ep: l = ep
  34.         CASE IS < em: l = em
  35.     END SELECT
  36.     l$ = LEFT$(t$, l - 1) 'The left of the SN
  37.     r$ = MID$(t$, l + 1): r&& = VAL(r$) 'The right of the SN, turned into a workable long
  38.     IF INSTR(l$, ".") THEN 'Location of the decimal, if any
  39.         IF r&& > 0 THEN
  40.             r&& = r&& - LEN(l$) + 2
  41.         ELSE
  42.             r&& = r&& + 1
  43.         END IF
  44.         l$ = LEFT$(l$, 1) + MID$(l$, 3)
  45.     END IF
  46.     SELECT CASE r&&
  47.         CASE 0 'what the heck? We solved it already?
  48.             'l$ = l$
  49.         CASE IS < 0
  50.             FOR i = 1 TO (-r&& - 1)
  51.                 l$ = "0" + l$
  52.             NEXT
  53.             l$ = "0." + l$
  54.         CASE ELSE
  55.             FOR i = 1 TO r&&
  56.                 l$ = l$ + "0"
  57.             NEXT
  58.             l$ = l$
  59.     END SELECT
  60.     IF sign$ = "" THEN sign$ = " "
  61.     N2S$ = sign$ + l$
  62.  
« Last Edit: September 06, 2020, 04:34:05 PM by SMcNeill »
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 2782
    • Steve’s QB64 Archive Forum
Re: Scientific or exponential notation remover
« Reply #3 on: September 06, 2020, 04:37:11 PM »
And a version which does a little better keeping formatting looking the same with our results:

Code: QB64: [Select]
  1. _TITLE "N2S$ testing for a scientific notation remover" 'b+ 2020-09-04
  2.  
  3. ' looks pretty good except for one little bug
  4.  
  5. IF 1 THEN ' < 0 to skip section, 1 to run section
  6.     n = 1 ' has an odd bug jump -7 to -8 moves right 1 extra 0
  7.     FOR i = 0 TO 20
  8.         PRINT i, N2S$(STR$(n * 10 ^ -i));
  9.         LOCATE CSRLIN, 50: PRINT N2S$(STR$(n * 10 ^ i))
  10.     NEXT
  11.  
  12. IF 0 THEN '  < 0 to skip section, 1 to run section
  13.     n## = 1 ' but this OK too
  14.     'n## = 27.0123456789 'OK
  15.     'n## = (1 / 3) 'OK
  16.     FOR i = 0 TO 20
  17.         PRINT i, N2S$(STR$(n## * 10 ^ -i));
  18.         LOCATE CSRLIN, 54: PRINT N2S$(STR$(n## * 10 ^ i))
  19.     NEXT
  20.  
  21. FUNCTION N2S$ (EXP$) 'remove scientific Notation to String (~40 LOC)
  22.     'SMcNeill Jan 7, 2020 ref: https://www.qb64.org/forum/index.php?topic=1555.msg112989#msg112989
  23.     'Last Function in code marked Best Answer (removed debug comments and blank lines added these 2 lines.)
  24.     t$ = LTRIM$(RTRIM$(EXP$))
  25.     IF LEFT$(t$, 1) = "-" OR LEFT$(t$, 1) = "N" THEN sign$ = "-": t$ = MID$(t$, 2)
  26.     dp = INSTR(t$, "D+"): dm = INSTR(t$, "D-")
  27.     ep = INSTR(t$, "E+"): em = INSTR(t$, "E-")
  28.     check1 = SGN(dp) + SGN(dm) + SGN(ep) + SGN(em)
  29.     IF check1 < 1 OR check1 > 1 THEN N2S = EXP$: EXIT SUB 'If no scientic notation is found, or if we find more than 1 type, it's not SN!
  30.     SELECT CASE l 'l now tells us where the SN starts at.
  31.         CASE IS < dp: l = dp
  32.         CASE IS < dm: l = dm
  33.         CASE IS < ep: l = ep
  34.         CASE IS < em: l = em
  35.     END SELECT
  36.     l$ = LEFT$(t$, l - 1) 'The left of the SN
  37.     r$ = MID$(t$, l + 1): r&& = VAL(r$) 'The right of the SN, turned into a workable long
  38.     IF INSTR(l$, ".") THEN 'Location of the decimal, if any
  39.         IF r&& > 0 THEN
  40.             r&& = r&& - LEN(l$) + 2
  41.         ELSE
  42.             r&& = r&& + 1
  43.         END IF
  44.         l$ = LEFT$(l$, 1) + MID$(l$, 3)
  45.     END IF
  46.     SELECT CASE r&&
  47.         CASE 0 'what the heck? We solved it already?
  48.             'l$ = l$
  49.         CASE IS < 0
  50.             FOR i = 1 TO (-r&& - 1)
  51.                 l$ = "0" + l$
  52.             NEXT
  53.             l$ = "." + l$
  54.         CASE ELSE
  55.             FOR i = 1 TO r&&
  56.                 l$ = l$ + "0"
  57.             NEXT
  58.             l$ = l$
  59.     END SELECT
  60.     IF sign$ = "" THEN sign$ = " "
  61.     N2S$ = sign$ + l$
  62.  

https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline bplus

  • Forum Resident
  • Posts: 5300
  • B+ Knot again!
Re: Scientific or exponential notation remover
« Reply #4 on: September 06, 2020, 06:29:06 PM »
Thanks @SMcNeill

I suspected it had something to do with switching from no notation to notation with the number string coming in.

Funny, you added a space if sign was positive whereas I had trimmed space off before sending the number string back if it didn't have notation in it. :)

Offline bplus

  • Forum Resident
  • Posts: 5300
  • B+ Knot again!
Re: Scientific or exponential notation remover
« Reply #5 on: September 06, 2020, 07:08:23 PM »
@SMcNeill  OK now big problem with floats as input: they are all off by 1 zero in decimals when N2S$ is not just trimming the input string. Before it was just the integer 1 that failed as input but other non float inputs seemed OK.

I have * all outputs when N2S$ only trims the input string
Code: QB64: [Select]
  1. _TITLE "N2S$ testing for a scientific notation remover" 'b+ 2020-09-04
  2. ' looks pretty good except for one little bug
  3. ' 2020-09-06 fixed ? see comment line with this date
  4.  
  5.  
  6. IF 0 THEN ' < 0 to skip section, 1 to run section    2020-09-06 this section looks good!
  7.     n = 1 ' has an odd bug jump -7 to -8 moves right 1 extra 0     OK beautiful 2020-09-06!
  8.     'n = 0.003 ' 2020-09-06 this looks fine too
  9.     'n = 1000 / 3 '2020-09-06 fine!
  10.     FOR i = 0 TO 20
  11.         PRINT i, N2S$(STR$(n * 10 ^ -i));
  12.         LOCATE CSRLIN, 54: PRINT N2S$(STR$(n * 10 ^ i))
  13.     NEXT
  14.  
  15. IF 1 THEN '  < 0 to skip section, 1 to run section
  16.     n## = 1.0 ' but this OK too (when n=1 wasn't working)   2020-09-06 Now this is wrong!!!
  17.     n## = 1000 / 3 'OK                                      and this
  18.     n## = .003 'OK                                          and this
  19.     FOR i = 0 TO 20
  20.         'PRINT i, STR$(n## * 10 ^ -i), N2S$(STR$(n## * 10 ^ -i))
  21.         PRINT i, N2S$(STR$(n## * 10 ^ -i));
  22.         LOCATE CSRLIN, 54: PRINT N2S$(STR$(n## * 10 ^ i))
  23.     NEXT
  24.  
  25. FUNCTION N2S$ (EXP$) 'remove scientific Notation to String (~43 LOC)
  26.     DIM t$, sign$, L$, R$, r&&
  27.     DIM dp AS INTEGER, dm AS INTEGER, ep AS INTEGER, em AS INTEGER, check1 AS INTEGER, L AS INTEGER, i AS INTEGER
  28.     'SMcNeill Jan 7, 2020 ref: https://www.qb64.org/forum/index.php?topic=1555.msg112989#msg112989
  29.     'Last Function in code marked Best Answer (removed debug comments and blank lines added these 2 lines.)
  30.     t$ = _TRIM$(EXP$)
  31.     IF LEFT$(t$, 1) = "-" OR LEFT$(t$, 1) = "N" THEN sign$ = "-": t$ = MID$(t$, 2)
  32.     dp = INSTR(t$, "D+"): dm = INSTR(t$, "D-")
  33.     ep = INSTR(t$, "E+"): em = INSTR(t$, "E-")
  34.     check1 = SGN(dp) + SGN(dm) + SGN(ep) + SGN(em)
  35.     IF check1 < 1 OR check1 > 1 THEN N2S$ = _TRIM$(EXP$) + "*": EXIT SUB 'If no scientic notation is found, or if we find more than 1 type, it's not SN!
  36.     SELECT CASE L 'l now tells us where the SN starts at.
  37.         CASE IS < dp: L = dp
  38.         CASE IS < dm: L = dm
  39.         CASE IS < ep: L = ep
  40.         CASE IS < em: L = em
  41.     END SELECT
  42.     L$ = LEFT$(t$, L - 1) 'The left of the SN
  43.     R$ = MID$(t$, L + 1): r&& = VAL(R$) 'The right of the SN, turned into a workable long
  44.     IF INSTR(L$, ".") THEN 'Location of the decimal, if any
  45.         IF r&& > 0 THEN
  46.             r&& = r&& - LEN(L$) + 2
  47.         ELSE
  48.             r&& = r&& + 1
  49.         END IF
  50.         L$ = LEFT$(L$, 1) + MID$(L$, 3)
  51.     END IF
  52.     SELECT CASE r&&
  53.         CASE 0 'what the heck? We solved it already?
  54.             'l$ = l$
  55.         CASE IS < 0
  56.             FOR i = 1 TO (-r&& - 1) 'fix SMcNeill 2020-09-06
  57.                 L$ = "0" + L$
  58.             NEXT
  59.             L$ = "." + L$ ' 2020-09-06 removed 0 of "0." + L$  to keep consistent with other returns
  60.         CASE ELSE
  61.             FOR i = 1 TO r&&
  62.                 L$ = L$ + "0"
  63.             NEXT
  64.             L$ = L$
  65.     END SELECT
  66.     N2S$ = sign$ + L$
  67.  
  68.  

It seems if you get the floats correct the integers (or just 1 is off). Fix 1 and all the floats are off.

Offline bplus

  • Forum Resident
  • Posts: 5300
  • B+ Knot again!
Re: Scientific or exponential notation remover
« Reply #6 on: September 08, 2020, 04:38:29 PM »
Sorry @SMcNeill

You had it right the first time!

I finally tracked down the source of the bug. It was in the test, we needed to DIM i as INTEGER for the powers of 10.

Here is the proof:
Code: QB64: [Select]
  1. _TITLE "N2S$ testing for a scientific notation remover" 'b+ 2020-09-04
  2. ' source of bug tracked down 2020-09-08
  3. ' looks pretty good except for one little bug fixed now
  4.  
  5. 'It was because i was not dim'd as an integer!!!
  6. DIM i AS INTEGER '<<<<<<<<<<<<<<<<<<<< Oh man!!!!  this was the problem!!! Discovered 2020-09-08
  7.  
  8. IF 0 THEN ' < 0 to skip section, 1 to run section
  9.     DIM n AS INTEGER '<<<<<<<<<<< comment out to test single
  10.     n = 1 ' has an odd bug jump -7 to -8 moves right 1 extra 0   fixed!!
  11.     FOR i = 0 TO 20
  12.         PRINT i,
  13.         LOCATE CSRLIN, 5: PRINT N2S$(STR$(n * 10 ^ -i));
  14.         LOCATE CSRLIN, 54: PRINT N2S$(STR$(n * 10 ^ i))
  15.     NEXT
  16.     BEEP
  17.     n## = 1 ' but this OK too
  18.     'n## = 27.0123456789 'OK
  19.     'n## = (1 / 3) 'OK
  20.     FOR i = 0 TO 20
  21.         PRINT i;
  22.         LOCATE CSRLIN, 5: PRINT N2S$(STR$(n## * 10 ^ -i));
  23.         LOCATE CSRLIN, 54: PRINT N2S$(STR$(n## * 10 ^ i))
  24.     NEXT
  25.     BEEP
  26.  
  27. FUNCTION N2S$ (EXP$) 'remove scientific Notation to String (~40 LOC)
  28.     'SMcNeill Jan 7, 2020 ref: https://www.qb64.org/forum/index.php?topic=1555.msg112989#msg112989
  29.     'Last Function in code marked Best Answer (removed debug comments and blank lines added these 2 lines.)
  30.     t$ = LTRIM$(RTRIM$(EXP$))
  31.     IF LEFT$(t$, 1) = "-" OR LEFT$(t$, 1) = "N" THEN sign$ = "-": t$ = MID$(t$, 2)
  32.     dp = INSTR(t$, "D+"): dm = INSTR(t$, "D-")
  33.     ep = INSTR(t$, "E+"): em = INSTR(t$, "E-")
  34.     check1 = SGN(dp) + SGN(dm) + SGN(ep) + SGN(em)
  35.     IF check1 < 1 OR check1 > 1 THEN N2S = _TRIM$(EXP$): EXIT SUB 'If no scientic notation is found, or if we find more than 1 type, it's not SN!
  36.     SELECT CASE l 'l now tells us where the SN starts at.
  37.         CASE IS < dp: l = dp
  38.         CASE IS < dm: l = dm
  39.         CASE IS < ep: l = ep
  40.         CASE IS < em: l = em
  41.     END SELECT
  42.     l$ = LEFT$(t$, l - 1) 'The left of the SN
  43.     r$ = MID$(t$, l + 1): r&& = VAL(r$) 'The right of the SN, turned into a workable long
  44.     IF INSTR(l$, ".") THEN 'Location of the decimal, if any
  45.         IF r&& > 0 THEN
  46.             r&& = r&& - LEN(l$) + 2
  47.         ELSE
  48.             r&& = r&& + 1
  49.         END IF
  50.         l$ = LEFT$(l$, 1) + MID$(l$, 3)
  51.     END IF
  52.     SELECT CASE r&&
  53.         CASE 0 'what the heck? We solved it already?
  54.             'l$ = l$
  55.         CASE IS < 0
  56.             FOR i = 1 TO -r&&
  57.                 l$ = "0" + l$
  58.             NEXT
  59.             l$ = "." + l$
  60.         CASE ELSE
  61.             FOR i = 1 TO r&&
  62.                 l$ = l$ + "0"
  63.             NEXT
  64.             l$ = l$
  65.     END SELECT
  66.     N2S$ = sign$ + l$
  67.  

PS Changes: I am trimming the EXP$ when no exponent is found and I am using .xxxx not 0.xxxx
Among other reasons it makes this test very consistent in output between exponent mods and no exponent mods.
« Last Edit: September 08, 2020, 04:47:03 PM by bplus »

Offline MWheatley

  • Newbie
  • Posts: 57
Re: Scientific or exponential notation remover
« Reply #7 on: September 09, 2020, 06:00:08 PM »
Hi.

Where's the original post on this?  Happy to download the code and do some testing.

Malcolm

Offline bplus

  • Forum Resident
  • Posts: 5300
  • B+ Knot again!
Re: Scientific or exponential notation remover
« Reply #8 on: September 09, 2020, 07:01:17 PM »
Hi.

Where's the original post on this?  Happy to download the code and do some testing.

Malcolm

It's listed right with the N2S$ function.

Offline MWheatley

  • Newbie
  • Posts: 57
Re: Scientific or exponential notation remover
« Reply #9 on: September 15, 2020, 04:10:10 PM »
I'm sorry: "it's listed right" doesn't mean anything to me.  Where?

Malcolm

Offline bplus

  • Forum Resident
  • Posts: 5300
  • B+ Knot again!
Re: Scientific or exponential notation remover
« Reply #10 on: September 15, 2020, 04:16:31 PM »
I'm sorry: "it's listed right" doesn't mean anything to me.  Where?

Malcolm

"its listed right with the N2S$ function."

What you don't like my demo of the N2S$ Function? ;(

OK here it is highlighted from that function, so you can see it better.


FUNCTION N2S$ (EXP$) 'remove scientific Notation to String (~40 LOC)
    'SMcNeill Jan 7, 2020 ref: https://www.qb64.org/forum/index.php?topic=1555.msg112989#msg112989
    'Last Function in code marked Best Answer (removed debug comments and blank lines added these 2 lines.)

« Last Edit: September 15, 2020, 04:23:57 PM by bplus »