develooper Front page | perl.perl6.users | Postings from October 2021

Re: how do I turn a real into and array of Integers?

Thread Previous | Thread Next
From:
Bruce Gray
Date:
October 31, 2021 14:25
Subject:
Re: how do I turn a real into and array of Integers?
Message ID:
718852D9-FECF-4C36-89CE-97116CD42655@acm.org


> On Oct 31, 2021, at 6:10 AM, ToddAndMargo via perl6-users <perl6-users@perl.org> wrote:
> 
> On 10/31/21 01:43, Shlomi Fish wrote:
> 
>>> ("" ~ sqrt(2)).comb().grep(* ne ".").map(+*)
>> (1 4 1 4 2 1 3 5 6 2 3 7 3 0 9 5 1)
> 
> Cool!
> 
> my Int @x = ("" ~ sqrt(2)).comb().grep(* ne ".").map(+*)
> [1 4 1 4 2 1 3 5 6 2 3 7 3 0 9 5 1]
> 
> Is there a way to set how many digits I get?


[
	Aside: This aspect is underspecified: "how many digits"; do you want to specify the total digits, or digits-after-decimal-point?
		sqrt(333) = 18.24828759089466...
	If you say:
		my $wanted_digits = 5;
	, which of these are you wanting:
		1824828
		18248
	?
]

Like most languages, the "precision" (number of digits actually generated) for functions like sqrt() and sin() is fine-tuned to the "size" of Raku's floating point numbers (Num).
So:
    1. You cannot set Raku to produce only 3 decimal places. You *can* receive all the digits, then trim them down yourself.
    2. You cannot set Raku to produce more decimal places than it currently generates. You *can* use your own code to generate unlimited decimal places for most FP functions.

Examples:
# 1
my $wanted_digits = 15;
my Int @x = (sqrt(2) * (10**$wanted_digits)).floor.comb.map(+*);        # Will have incorrect digits at end, if $wanted_digits > 15.
my Int @x = sqrt(2).comb.grep(* ne ".").head($wanted_digits).map(+*);   # Will not produce over 17 digits for sqrt2, even if $wanted_digits is much higher, and the 17th digit is incorrect.

sqrt(333)
    18.24828759089466
my $wanted_digits = 10;
my Int @x = (sqrt(333) * (10**$wanted_digits)).floor.comb.map(+*);
    [1 8 2 4 8 2 8 7 5 9 0 8]
my Int @x = sqrt(333).comb.grep(* ne ".").head($wanted_digits).map(+*);
    [1 8 2 4 8 2 8 7 5 9]

# 2
Use http://rosettacode.org/wiki/Integer_roots#Raku , which will accurately produce absurdly large digits counts for [square|cube|any-integer] roots.
The code is my own translation from Python (which looks like it was based on https://en.wikipedia.org/wiki/Nth_root#Computing_principal_roots ), so I can answer questions on it.

sub integer_root ( Int $p where * >= 2, Int $n --> Int ) {
    my Int $d = $p - 1;
    my $guess = 10 ** ($n.chars div $p);
    my $iterator = { ( $d * $^x   +   $n div ($^x ** $d) ) div $p };
    my $endpoint = {      $^x      ** $p <= $n
                     and ($^x + 1) ** $p >  $n };
    return (+$guess, $iterator ... $endpoint).tail(2).min;
}
my $wanted_digits = 30;
say integer_root( 2, 333 * 100 ** $wanted_digits ).comb.head($wanted_digits).map(+*);
    (1 8 2 4 8 2 8 7 5 9 0 8 9 4 6 5 9 0 6 6 9 9 9 0 5 2 7 3 5 6)


Afterthought:
Re-reading the thread and OP, I see that you might simply need to add the .head() method to the end of other (already kindly provided) code.
If you already have created the array, and it might be too long, you can do this as a separate statement:
	@y .= head($wanted_size);
If you truly are trying to limit the number of decimal places (as opposed to total array length), then you can factor in the size of the integer part, with something like this (only lightly tested) code:
	@y .= head($wanted_decimal_places + $original_number.sqrt.floor.chars);

-- 
Hope this helps,
Bruce Gray (Util of PerlMonks)


Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About