Specify the number of decimal digits on the explicit generator of a sequence in Raku
Asked Answered
S

2

10

I've written a simple code:

sub euler-ex ($x) of Seq {
   1, { $x**++$ / [×] 1 .. ++$ } ... Inf }
say " 5: " ~ euler-ex(5)[^20]  ~ " = " ~ [+](euler-ex(5)[^20]);

The output:

5: 1 5 12.5 20.833333 26.041667 26.041667 21.701389 15.500992 9.68812 5.382289 2.6911445 1.22324748 0.50968645 0.19603325 0.07001187499 0.023337291662 0.0072929036444 0.00214497166011 0.000595825461143 0.000156796173985 = 148.41310786833832

How to specify the number of digits on that output, i.e. on the decimals coming out of the explicit generator of the sequence?

Snowstorm answered 1/11, 2022 at 16:43 Comment(2)
Hi @Lars. If neither of the answers are acceptable, but you have a solution (perhaps building on one or both of them), please consider writing an answer with that solution, and then accepting your own answer to helpfully guide future readers, and/or, if one or both answers are already acceptable, accept one, or, if you don't yet know of an acceptable solution, add a comment below whichever is closer, or under both of them, about what's missing. Thanks!Competent
@Competent Thank you for pointing it out. I took the first answer as accepted answer but I just happened to forget to mark it as such :(. Actually, I knew the fmt method 2 years ago while I was learning and frequently using Raku but after a long pause I had completely forgot it. So, that answer has been a nice reminder too :)Snowstorm
T
10

You can change the last line to

say " 5: " ~ euler-ex(5)[^20].fmt("%0.10f")  ~ "=" ~ [+](euler-ex(5)[^20]).fmt("%0.10f");

and get output like

 5: 1.0000000000 5.0000000000 12.5000000000 20.8333333333 26.0416666667 26.0416666667 21.7013888889 15.5009920635 9.6881200397 5.3822889109 2.6911444555 1.2232474798 0.5096864499 0.1960332500 0.0700118750 0.0233372917 0.0072929036 0.0021449717 0.0005958255 0.0001567962=148.4131078683

You might be interested to know that this sequence is generating Rats, so you could get the exact value if you want. You can see the "raw" values with

dd euler-ex(5)[^20];

(1, 5.0, 12.5, <125/6>, <625/24>, <625/24>, <3125/144>, <15625/1008>, <78125/8064>, <390625/72576>, <390625/145152>, <1953125/1596672>, <9765625/19160064>, <48828125/249080832>, <244140625/3487131648>, <244140625/10461394944>, <1220703125/167382319104>, <6103515625/2845499424768>, <30517578125/51218989645824>, <152587890625/973160803270656>)
Temperamental answered 1/11, 2022 at 19:24 Comment(1)
Thank you for the answer. It worked out when I added fmt("%0.2f") , it printed out neat 2 digit decimals. Thank you for the hint on showing the raw values, too.Snowstorm
A
5

You can round a number to wanted scale:

>>> 12.8471 .round(0.01)
12.85

12.8471 is rounded to the nearest multiple of 0.01; effectively, 2 decimal places.

You have a sequence of numbers, so map is there:

>>> (1, * + 𝑒 ... *) .head(5)
(1 3.718281828459045 6.43656365691809 9.154845485377136 11.87312731383618)

>>> (1, * + 𝑒 ... *) .map(*.round(0.01)) .head(5)
(1 3.72 6.44 9.15 11.87)

So for, e.g., 2 decimal points, need 0.01 == 10 ** -2; then we can argumentize this to the function:

sub euler-ex($x, Int :$digits) of Seq {
   my $seq := 1, { $x ** ++$ / [×] 1 .. ++$ } ... Inf;
   $digits
       ?? $seq.map(*.round(10 ** -$digits))
       !! $seq
}

>>> euler-ex(5).head(6)
(1 5 12.5 20.833333 26.041667 26.041667)

>>> euler-ex(5, :3digits).head(6)
(1 5 12.5 20.833 26.042 26.042)

If $digits is supplied (and nonzero...), the sequence will be returned back with its computed values rounded to that many decimal places. Otherwise, as is.


Noting that round gives back a numeric value (e.g., Rational above), and 12.3. round(0.01) would give 12.3 not 12.30, i.e., trailing zeros are not put. If that is wanted, .fmt as the other answer (but in map; or sprintf) is possible (noting that they give strings).

Advisable answered 1/11, 2022 at 20:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.