Roku Developer Program

Join our online forum to talk to Roku developers and fellow channel creators. Ask questions, share tips with the community, and find helpful resources.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
EnTerr
Roku Guru

No Str() for Double?

If i call `str()` on Double, seems it gets coerced to Float first and that doesn't always end well:
BSD> d = 1e40#
BSD> ? d, type(d)
1e+40 Double
BSD> ? str(d)
inf
BSD> ? d.toStr()
Member function not found in BrightScript Component or interface. (runtime error &hf4) in $LIVECOMPILE(153)

Comments? Is there interface like ifIntOps.toStr() tucked somewhere?
0 Kudos
8 REPLIES 8
TheEndless
Channel Surfer

Re: No Str() for Double?

As usual, I have a hack for that... and this one is very much a hack... 😉
        output = Str(input)
If output.InStr("e+") > -1 Then
exponent = 9
divisor# = 10 ^ exponent
high% = Int(input / divisor#)
low% = input - (high% * divisor#)
output = high%.ToStr() + PadLeft(low%.ToStr(), "0", exponent)
End If
Return output
My Channels: http://roku.permanence.com - Twitter: @TheEndlessDev
Instant Watch Browser (NetflixIWB), Aquarium Screensaver (AQUARIUM), Clever Clocks Screensaver (CLEVERCLOCKS), iTunes Podcasts (ITPC), My Channels (MYCHANNELS)
0 Kudos
EnTerr
Roku Guru

Re: No Str() for Double?

"TheEndless" wrote:
As usual, I have a hack for that... and this one is very much a hack... 😉

You are Master Lemonade Maker, indeed! 🙂 Here i assume
function padLeft(s, ch, toLen): 
return string(toLen - len(s), ch) + s
end function

I have not tried it but just from reading the code seems it has a particular, limited use - avoiding exponent notation where dividing by 1,000,000,000 can help? "Milliseconds since epoch" comes to mind. But it won't work outside specific range or say for 0.00001

PS. ok, my curiosity got the better of me and i checked:
BrightScript Debugger> for i = 5 to 20: d= 10# ^ i: ?i, str(d), doubleToStr(d): end for
5 100000 100000
6 1000000 1000000
7 1e+07 0010000000
8 1e+08 0100000000
9 1e+09 1000000000
10 1e+10 10000000000
11 1e+11 100000000000
12 1e+12 1000000000000
13 1e+13 10000000000000
14 1e+14 100000000000000
15 1e+15 1000000000000000
16 1e+16 10000000000000000
17 1e+17 100000000000000000
18 1e+18 1000000000000000000
19 1e+19 21474836472147483647
20 1e+20 21474836472147483647

So it works within 1e9 to 1e18, broken above that, weird for 1e7 and 1e8 decades
0 Kudos
EnTerr
Roku Guru

Re: No Str() for Double?

    0 Kudos
    TheEndless
    Channel Surfer

    Re: No Str() for Double?

    "EnTerr" wrote:
    So it works within 1e9 to 1e18, broken above that, weird for 1e7 and 1e8 decades

    Yeah, you'll notice in my code that I made the exponent configurable. 9 worked for everything I needed it for when I wrote the code which was primarily converting timestamps in millisecond form, as you suspected.
    My Channels: http://roku.permanence.com - Twitter: @TheEndlessDev
    Instant Watch Browser (NetflixIWB), Aquarium Screensaver (AQUARIUM), Clever Clocks Screensaver (CLEVERCLOCKS), iTunes Podcasts (ITPC), My Channels (MYCHANNELS)
    0 Kudos
    EnTerr
    Roku Guru

    Re: No Str() for Double?

    "TheEndless" wrote:
    Yeah, you'll notice in my code that I made the exponent configurable. 9 worked for everything I needed it for when I wrote the code which was primarily converting timestamps in millisecond form, as you suspected.

    If it came out harsh, i did not mean it that way - rather wanted to point out the range where it works. It's not easy to write universal function - the other day i was thinking i can write one that can "tease out" all the double precision by using str() and jacking up or down the decades, then rinse and repeat. After closer look, technically it's possible but a PITA, many cases and there is the rounding of the last digit too. Doing
    d=1.2345678987654321# : for i=-20 to 20: dd= d * 10#^i : ? i, dd, str(dd): end for
    shows the patterns, there are cases (a) below 1e-4, (b) 1e-4 to 1e6, (c) 1e7 to 1e13 (d) above 1e14. It will take me a whole day to iron it out, no point for me crossing that river yet.

    The thing is that functionality - converting Double to String - already exists in the interpreter: printing doubles works, it is just not exposed.

    Roku*, how about filing enhancement request: to either add `roDouble.toStr()` and `roString.toDouble()`. Alternatively make `str()` a double->string function instead of float->string (precision won't go down; i am a bit fuzzy on C but i think K&R was saying results of float operations are always double); ditto for `val(str) -> double`. It may or may not happen but suggestion be logged; there are real-life use cases (like milliseconds since epoch).
    0 Kudos
    TheEndless
    Channel Surfer

    Re: No Str() for Double?

    How about this for a hack? Works for 1e-4 to 1e+13...
      output = formatJSON({double: input})
    output = output.Mid(output.InStr(":") + 1)
    output = output.Mid(0, output.InStr("}"))
    Return output.Trim()
    My Channels: http://roku.permanence.com - Twitter: @TheEndlessDev
    Instant Watch Browser (NetflixIWB), Aquarium Screensaver (AQUARIUM), Clever Clocks Screensaver (CLEVERCLOCKS), iTunes Podcasts (ITPC), My Channels (MYCHANNELS)
    0 Kudos
    EnTerr
    Roku Guru

    Re: No Str() for Double?

    "TheEndless" wrote:
    How about this for a hack? Works for 1e-4 to 1e+13...
      output = formatJSON({double: input})
    output = output.Mid(output.InStr(":") + 1)
    output = output.Mid(0, output.InStr("}"))
    Return output.Trim()

    Nope?
    I admire the creative though, got excited for a moment but seems 'twas too good to be true:
    BrightScript Debugger> fn = function(x): output = formatJSON({double:x}): output = output.Mid(output.InStr(":") + 1): output = output.Mid(0, output.InStr("}")): Return output.Trim(): end function
    BrightScript Debugger> d = 1.2345678987654321# : for i=-5 to 20: dd = d*10#^i: ? i, dd, str(dd), fn(dd): end for
    -5 1.2345678987654e-05 1.234568e-05 1.23457e-05
    -4 0.00012345678987654 0.0001234568 0.000123457
    -3 0.0012345678987654 0.001234568 0.00123457
    -2 0.012345678987654 0.01234568 0.0123457
    -1 0.12345678987654 0.1234568 0.123457
    0 1.2345678987654 1.234568 1.23457
    1 12.345678987654 12.34568 12.3457
    2 123.45678987654 123.4568 123.457
    3 1234.5678987654 1234.568 1234.57
    4 12345.678987654 12345.68 12345.7
    5 123456.78987654 123456.8 123457
    6 1234567.8987654 1234568 1.23457e+06
    7 12345678.987654 1.234568e+07 1.23457e+07
    8 123456789.87654 1.234568e+08 1.23457e+08
    9 1234567898.7654 1.234568e+09 1.23457e+09
    10 12345678987.654 1.234568e+10 1.23457e+10
    11 123456789876.54 1.234568e+11 1.23457e+11
    12 1234567898765.4 1.234568e+12 1.23457e+12
    13 12345678987654 1.234568e+13 1.23457e+13
    14 1.2345678987654e+14 1.234568e+14 1.23457e+14
    15 1.2345678987654e+15 1.234568e+15 1234567898765432
    16 1.2345678987654e+16 1.234568e+16 1.234567899e+16
    17 1.2345678987654e+17 1.234568e+17 1.234567899e+17
    18 1.2345678987654e+18 1.234568e+18 1.234567899e+18
    19 1.2345678987654e+19 1.234568e+19 1.234567899e+19
    20 1.2345678987654e+20 1.234568e+20 1.234567899e+20


    So if any difference, it's that formatJSON has 1 digit less precision than str(). It reminds me of this cartoon i saw once upon a child.


    PS. except for 1e15... WAT?
    0 Kudos
    TheEndless
    Channel Surfer

    Re: No Str() for Double?

    "EnTerr" wrote:
    Nope?
    I admire the creative though, got excited for a moment but seems 'twas too good to be true:

    Ok.. hrmm.. I tested it with 1.0#, not 1.2345678987654321#. 1.0# gives much better results :P... even better than ?, for that matter.:?
    BrightScript Debugger> d = 1.0# : for i=-5 to 15: dd = d*10#^i: ? i, dd, str(dd), fn(dd): end for
    -5 1e-05 1e-05 1e-05
    -4 0.0001 0.0001 0.0001
    -3 0.001 0.001 0.001
    -2 0.01 0.01 0.01
    -1 0.1 0.1 0.1
    0 1 1 1
    1 10 10 10
    2 100 100 100
    3 1000 1000 1000
    4 10000 10000 10000
    5 100000 100000 100000
    6 1000000 1000000 1000000
    7 10000000 1e+07 10000000
    8 100000000 1e+08 100000000
    9 1000000000 1e+09 1000000000
    10 10000000000 1e+10 10000000000
    11 100000000000 1e+11 100000000000
    12 1000000000000 1e+12 1000000000000
    13 10000000000000 1e+13 10000000000000
    14 1e+14 1e+14 100000000000000
    15 1e+15 1e+15 1000000000000000

    EDIT: Looks like 6 decimal places might be the limit for consistent results for fractions...
    BrightScript Debugger> d = 1.123456# : for i=-5 to 20: dd# = d*10#^i: ? i, dd#, str(dd#), fn(dd#): end for
    -5 1.123456e-05 1.123456e-05 1.12346e-05
    -4 0.0001123456 0.0001123456 0.000112346
    -3 0.001123456 0.001123456 0.00112346
    -2 0.01123456 0.01123456 0.0112346
    -1 0.1123456 0.1123456 0.112346
    0 1.123456 1.123456 1.12346
    1 11.23456 11.23456 11.2346
    2 112.3456 112.3456 112.346
    3 1123.456 1123.456 1123.46
    4 11234.56 11234.56 11234.6
    5 112345.6 112345.6 112346
    6 1123456 1123456 1123456
    7 11234560 1.123456e+07 11234560
    8 112345600 1.123456e+08 112345600
    9 1123456000 1.123456e+09 1123456000
    10 11234560000 1.123456e+10 11234560000
    11 112345600000 1.123456e+11 112345600000
    12 1123456000000 1.123456e+12 1123456000000
    13 11234560000000 1.123456e+13 11234560000000
    14 1.123456e+14 1.123456e+14 112345600000000
    15 1.123456e+15 1.123456e+15 1123456000000000
    16 1.123456e+16 1.123456e+16 1.123456e+16
    17 1.123456e+17 1.123456e+17 1.123456e+17
    18 1.123456e+18 1.123456e+18 1.123456e+18
    19 1.123456e+19 1.123456e+19 1.123456e+19
    20 1.123456e+20 1.123456e+20 1.123456e+20

    BrightScript Debugger> d = 1.1234567# : for i=-5 to 20: dd# = d*10#^i: ? i, dd#, str(dd#), fn(dd#): end for
    -5 1.1234567e-05 1.123457e-05 1.12346e-05
    -4 0.00011234567 0.0001123457 0.000112346
    -3 0.0011234567 0.001123457 0.00112346
    -2 0.011234567 0.01123457 0.0112346
    -1 0.11234567 0.1123457 0.112346
    0 1.1234567 1.123457 1.12346
    1 11.234567 11.23457 11.2346
    2 112.34567 112.3457 112.346
    3 1123.4567 1123.457 1123.46
    4 11234.567 11234.57 11234.6
    5 112345.67 112345.7 112346
    6 1123456.7 1123457 1.12346e+06
    7 11234567 1.123457e+07 11234567
    8 112345670 1.123457e+08 112345670
    9 1123456700 1.123457e+09 1123456700
    10 11234567000 1.123457e+10 11234567000
    11 112345670000 1.123457e+11 112345670000
    12 1123456700000 1.123457e+12 1123456700000
    13 11234567000000 1.123457e+13 11234567000000
    14 1.1234567e+14 1.123457e+14 112345670000000
    15 1.1234567e+15 1.123457e+15 1123456700000000
    16 1.1234567e+16 1.123457e+16 1.1234567e+16
    17 1.1234567e+17 1.123457e+17 1.1234567e+17
    18 1.1234567e+18 1.123457e+18 1.1234567e+18
    19 1.1234567e+19 1.123457e+19 1.1234567e+19
    20 1.1234567e+20 1.123457e+20 1.1234567e+20
    BrightScript Debugger>

    That being said, since the ultimate goal was for fake 64-bit integers, it works beautifully for that... better than both ? and Str(), but then, so did my original method...
    BrightScript Debugger> ?fn(1234567890123456#)
    1234567890123456
    BrightScript Debugger> ?1234567890123456#
    1.2345678901235e+15
    BrightScript Debugger> ?Str(1234567890123456#)
    1.234568e+15
    My Channels: http://roku.permanence.com - Twitter: @TheEndlessDev
    Instant Watch Browser (NetflixIWB), Aquarium Screensaver (AQUARIUM), Clever Clocks Screensaver (CLEVERCLOCKS), iTunes Podcasts (ITPC), My Channels (MYCHANNELS)
    0 Kudos