Radical of an integer: Difference between revisions

From Rosetta Code
Content added Content deleted
m (→‎{{header|J}}: include bonus)
m (→‎{{header|Julia}}: add stretch)
Line 219: Line 219:
println("\nBreakdown of numbers of distinct prime factors for positive integers from 1 to 1,000,000:")
println("\nBreakdown of numbers of distinct prime factors for positive integers from 1 to 1,000,000:")
histogram(map(radicallength, 1:1_000_000), nbins = 8)
histogram(map(radicallength, 1:1_000_000), nbins = 8)

println("\nCheck on breakdown:")
primecount = length(primes(1_000_000)) # count of primes to 1 million
powerscount = mapreduce(p -> Int(floor(6 / log10(p)) - 1), +, primes(1000))
println("Prime count to 1 million: ", lpad(primecount, 6))
println("Prime powers less than 1 million: ", lpad(powerscount, 6))
println("Subtotal:", lpad(primecount + powerscount, 32))
println("The integer 1 has 0 prime factors: ", lpad(1, 6))
println("-"^41, "\n", "Overall total:", lpad(primecount + powerscount + 1, 27))
</syntaxhighlight>{{out}}
</syntaxhighlight>{{out}}
<pre>
<pre>
Line 246: Line 255:
└ ┘
└ ┘
Frequency
Frequency

Check on breakdown:
Prime count to 1 million: 78498
Prime powers less than 1 million: 236
Subtotal: 78734
The integer 1 has 0 prime factors: 1
-----------------------------------------
Overall total: 78735
</pre>
</pre>

=={{header|Pascal}}==
=={{header|Pascal}}==
==={{header|Free Pascal}}===
==={{header|Free Pascal}}===

Revision as of 20:41, 23 May 2023

Radical of an integer is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.
Definition

The radical of a positive integer is defined as the product of its distinct prime factors.

Although the integer 1 has no prime factors, its radical is regarded as 1 by convention.

Example

The radical of 504 = 2³ x 3² x 7 is: 2 x 3 x 7 = 42.

Task

1. Find and show on this page the radicals of the first 50 positive integers.

2. Find and show the radicals of the integers: 99999, 499999 and 999999.

3. By considering their radicals, show the distribution of the first one million positive integers by numbers of distinct prime factors (hint: the maximum number of distinct factors is 7).

Bonus

By (preferably) using an independent method, calculate the number of primes and the number of powers of primes less than or equal to one million and hence check that your answer in 3. above for numbers with one distinct prime is correct.

Related tasks
References


J

   ~.&.q: 1+i.5 10   NB. radicals of first 50 positive integers
 1  2  3  2  5  6  7  2  3 10
11  6 13 14 15  2 17  6 19 10
21 22 23  6  5 26  3 14 29 30
31  2 33 34 35  6 37 38 39 10
41 42 43 22 15 46 47  6  7 10
   ~.&.q: 99999 499999 999999   NB. radicals of these three...
33333 3937 111111
   (~.,.#/.~) 1>.#@~.@q: 1+i.1e6   NB.  distribution of number of prime factors of first million positive integers
1  78735
2 288726
3 379720
4 208034
5  42492
6   2285
7      8
   p:inv 1e6   NB. number of primes not exceeding 1 million
78498
   +/_1+<.(i.&.(p:inv) 1000)^.1e6  NB. count of prime powers (square or above) up to 1 million
236
   78498+236+1   NB. and we "claimed" that 1 had a prime factor
78735

jq

Adapted from Wren

Works with: jq

Also works with gojq, the Go implementations of jq, except that gojq is likely to run out of memory before completing part2.

# Utility functions
def lpad($len): tostring | ($len - length) as $l | (" " * $l) + .;

def prod(s): reduce s as $x (1; . * $x);

def sum(s): reduce s as $x (0; . + $x);

def uniq(s):
  foreach s as $x (null;
    if . and $x == .[0] then .[1] = false
    else [$x, true]
    end;
    if .[1] then .[0] else empty end);


# Prime number functions

# Returns the prime factors of . in order using a wheel with basis [2, 3, 5].
def primeFactors:
  def out($i): until (.n % $i != 0; .factors += [$i] | .n = ((.n/$i)|floor) );
  if . < 2 then []
  else [4, 2, 4, 2, 4, 6, 2, 6] as $inc
    | { n: .,
        factors: [] }
    | out(2)
    | out(3)
    | out(5)
    | .k = 7
    | .i = 0
    | until(.k * .k > .n;
        if .n % .k == 0
        then .factors += [.k]
        | .n = ((.n/.k)|floor)
        else .k += $inc[.i]
        | .i = ((.i + 1) % 8)
        end)
    | if .n > 1 then .factors += [.n] else . end

  | .factors
  end;

# Input:  a positive integer
# Output: an array, $a, of length .+1 such that
#         $a[$i] is $i if $i is prime, and false otherwise.
def primeSieve:
  # erase(i) sets .[i*j] to false for integral j > 1
  def erase($i):
    if .[$i] then
      reduce (range(2*$i; length; $i)) as $j (.; .[$j] = false) 
    else .
    end;
  (. + 1) as $n
  | (($n|sqrt) / 2) as $s
  | [null, null, range(2; $n)]
  | reduce (2, 1 + (2 * range(1; $s))) as $i (.; erase($i)) ;

# Number of primes up to and including .
def primeCount:
  sum(primeSieve[] | select(.) | 1);


## Radicals

def task1:
{ radicals: [0],
  counts:   [range(0;8)|0] }
| .radicals[1] = 1
| .counts[1] = 1 
| foreach range(2; 1+1e6) as $i (.;
    .factors = [uniq($i|primeFactors[])]
    | (.factors|length) as $fc
    | .counts[$fc] += 1
    | if $i <= 50 then .radicals[$i] = prod(.factors[]) else . end ;
    
    if $i == 50 
    then "The radicals for the first 50 positive integers are:",
         (.radicals[1:] | _nwise(10) | map(lpad(4)) | join(" ")),
	 ""

    elif $i | IN( 99999, 499999, 999999)
    then "Radical for \($i|lpad(8)): \(prod(.factors[])|lpad(8))"
    elif $i == 1e6
    then  "\nBreakdown of numbers of distinct prime factors",
        "for positive integers from 1 to 1,000,000:",
        (range(1; 8) as $i
         | "  \($i): \(.counts[$i]|lpad(8))"),
         "    ---------",
         "    \(sum(.counts[]))"
    else empty
    end);

def task2:
  def pad: lpad(6);
 
  (1000|primeSieve|map(select(.))) as $primes1k
  | { pcount: (1e6|primeCount),
      ppcount: 0 }
  | reduce $primes1k[] as $p (.;
      .p2 = $p
      | .done = false
      | until(.done;
          .p2 *= $p
          | if .p2 > 1e6 then .done = true
	    else .ppcount += 1
	    end ) )
  | "\nFor primes or powers (>1) thereof <= 1,000,000:",
    "  Number of primes   = \(.pcount|pad)",
    "  Number of powers   = \(.ppcount|pad)",
    "  Add 1 for number 1 = \(1|pad)",
    "                       ------",
    "                       \( (.pcount + .ppcount + 1)|pad)" ;

task1, task2
The radicals for the first 50 positive integers are:
   1    2    3    2    5    6    7    2    3   10
  11    6   13   14   15    2   17    6   19   10
  21   22   23    6    5   26    3   14   29   30
  31    2   33   34   35    6   37   38   39   10
  41   42   43   22   15   46   47    6    7   10

Radical for    99999:    33333
Radical for   499999:     3937
Radical for   999999:   111111

Breakdown of numbers of distinct prime factors
for positive integers from 1 to 1,000,000:
  1:    78735
  2:   288726
  3:   379720
  4:   208034
  5:    42492
  6:     2285
  7:        8
    ---------
      1000000

For primes or powers (>1) thereof <= 1,000,000:
  Number of primes   =  78498
  Number of powers   =    236
  Add 1 for number 1 =      1
                       ------
                        78735

Julia

using Formatting, Primes, UnicodePlots

radical(n) = prod(map(first, factor(n).pe))
radicallength(n) = length(factor(n).pe)

println("The radicals for the first 50 positive integers are:")
foreach(p -> print(rpad(p[2], 4), p[1] % 10 == 0 ? "\n" : ""), enumerate(map(radical, 1:50)))

for i in [99999, 499999, 999999]
    println("\nRadical for ", format(i, commas=true), ": ", format(radical(i), commas=true))
end

println("\nBreakdown of numbers of distinct prime factors for positive integers from 1 to 1,000,000:")
histogram(map(radicallength, 1:1_000_000), nbins = 8)

println("\nCheck on breakdown:")
primecount = length(primes(1_000_000)) # count of primes to 1 million
powerscount = mapreduce(p -> Int(floor(6 / log10(p)) - 1), +, primes(1000))
println("Prime count to 1 million:          ", lpad(primecount, 6))
println("Prime powers less than 1 million:  ", lpad(powerscount, 6))
println("Subtotal:", lpad(primecount + powerscount, 32))
println("The integer 1 has 0 prime factors: ", lpad(1, 6))
println("-"^41, "\n", "Overall total:", lpad(primecount + powerscount + 1, 27))
Output:
The radicals for the first 50 positive integers are:
1   2   3   2   5   6   7   2   3   10  
11  6   13  14  15  2   17  6   19  10
21  22  23  6   5   26  3   14  29  30
31  2   33  34  35  6   37  38  39  10
41  42  43  22  15  46  47  6   7   10

Radical for 99,999: 33,333

Radical for 499,999: 3,937

Radical for 999,999: 111,111

Breakdown of numbers of distinct prime factors for positive integers from 1 to 1,000,000:
              ┌                                        ┐ 
   [0.0, 1.0) ┤▏ 1                                      
   [1.0, 2.0) ┤██████▌ 78 734                           
   [2.0, 3.0) ┤███████████████████████▌ 288 726         
   [3.0, 4.0) ┤███████████████████████████████  379 720 
   [4.0, 5.0) ┤████████████████▉ 208 034                
   [5.0, 6.0) ┤███▌ 42 492                              
   [6.0, 7.0) ┤▎ 2 285                                  
   [7.0, 8.0) ┤▏ 8                                      
              └                                        ┘
                               Frequency

Check on breakdown:
Prime count to 1 million:           78498
Prime powers less than 1 million:     236
Subtotal:                           78734
The integer 1 has 0 prime factors:      1
-----------------------------------------
Overall total:                      78735

Pascal

Free Pascal

program Radical;
{$IFDEF FPC}  {$MODE DELPHI}{$Optimization ON,ALL} {$ENDIF}
{$IFDEF WINDOWS}{$APPTYPE CONSOLE}{$ENDIF}
//much faster would be
//https://rosettacode.org/wiki/Factors_of_an_integer#using_Prime_decomposition
const
  LIMIT = 1000*1000;
  DeltaMod235 : array[0..7] of Uint32 = (4, 2, 4, 2, 4, 6, 2, 6);

type
  tRadical = record
               number,radical,PrFacCnt: Uint64;
               isPrime : boolean;
             end;
  function GetRadical(n: UInt64):tRadical;forward;

function CommaUint(n : Uint64):AnsiString;
//commatize only positive Integers
var
  fromIdx,toIdx :Int32;
  pRes : pChar;
Begin
  str(n,result);
  fromIdx := length(result);
  toIdx := fromIdx-1;
  if toIdx < 3 then
    exit;

  toIdx := 4*(toIdx DIV 3)+toIdx MOD 3 +1 ;
  setlength(result,toIdx);
  pRes := @result[1];
  dec(pRes);
  repeat
    pRes[toIdx]   := pRes[FromIdx];
    pRes[toIdx-1] := pRes[FromIdx-1];
    pRes[toIdx-2] := pRes[FromIdx-2];
    pRes[toIdx-3] := ',';
    dec(toIdx,4);
    dec(FromIdx,3);
  until FromIdx<=3;
  while fromIdx>=1 do
  Begin
    pRes[toIdx] := pRes[FromIdx];
    dec(toIdx);
    dec(fromIdx);
  end;
end;

procedure OutRadical(n: Uint64);
Begin
  writeln('Radical for ',CommaUint(n):8,':',CommaUint(GetRadical(n).radical):8);
end;

function GetRadical(n: UInt64):tRadical;
var
  q,divisor, rest: UInt64;
  nxt : Uint32;
begin
  with result do
  Begin
    number := n;
    radical := n;
    PrFacCnt := 1;
    isPrime := false;
  end;

  if n <= 1 then
    EXIT;

  if n in [2,3,5,7,11,13,17,19,23,29,31] then
  Begin
    with result do
    Begin
      isprime := true;
      PrFacCnt := 1;
    end;
    EXIT;
  end;

  with result do
  Begin
    radical := 1;
    PrFacCnt := 0;
  end;

  rest := n;
  if rest AND 1 = 0 then
  begin
    with result do begin radical := 2; PrFacCnt:= 1;end;
    repeat
      rest := rest shr 1;
    until rest AND 1 <> 0;
  end;

  if rest < 3 then
    EXIT;
  q := rest DIV 3;
  if rest-q*3= 0 then
  begin
    with result do begin radical *= 3; inc(PrFacCnt);end;
    repeat
      rest := q;
      q := rest DIV 3;
    until rest-q*3 <> 0;
  end;

  if rest < 5 then
    EXIT;
  q := rest DIV 5;
  if rest-q*5= 0 then
  begin
    with result do begin radical *= 5;inc(PrFacCnt);end;
    repeat
      rest := q;
      q := rest DIV 5;
    until rest-q*5 <> 0;
  end;

  divisor := 7;
  nxt := 0;
  repeat;
    if rest < sqr(divisor) then
      BREAK;
    q := rest DIV divisor;
    if rest-q*divisor= 0 then
    begin
      with result do begin radical *= divisor; inc(PrFacCnt);end;
      repeat
        rest := q;
        q := rest DIV divisor;
      until rest-q*divisor <> 0;
    end;
    divisor += DeltaMod235[nxt];
    nxt := (nxt+1) AND 7;
  until false;
  //prime ?
  if rest = n then
    with result do begin radical := n;PrFacCnt:=1;isPrime := true; end
  else
    if rest >1 then
      with result do begin radical *= rest;inc(PrFacCnt);end;
end;

var
  Rad:tRadical;
  CntOfPrFac : array[0..9] of Uint32;
  j,sum,countOfPrimes,CountOfPrimePowers: integer;

begin
  writeln('The radicals for the first 50 positive integers are:');
  for j := 1 to 50 do
  Begin
    write (GetRadical(j).radical:4);
    if j mod 10 = 0 then
      Writeln;
  end;
  writeln;

  OutRadical( 99999);
  OutRadical(499999);
  OutRadical(999999);
  writeln;

  writeln('Breakdown of numbers of distinct prime factors');
  writeln('for positive integers from 1 to ',CommaUint(LIMIT));

  countOfPrimes:=0;
  CountOfPrimePowers :=0;
  For j := Low(CntOfPrFac) to High(CntOfPrFac) do
    CntOfPrFac[j] := 0;
  For j := 1 to LIMIT do
  Begin
    Rad := GetRadical(j);
    with rad do
    Begin
      IF isPrime then
        inc(countOfPrimes)
      else
        if (j>1)AND(PrFacCnt= 1) then
          inc(CountOfPrimePowers);
    end;
    inc(CntOfPrFac[Rad.PrFacCnt]);
  end;

  sum := 0;
  For j := Low(CntOfPrFac) to High(CntOfPrFac) do
    if CntOfPrFac[j] > 0 then
    Begin
      writeln(j:3,': ',CommaUint(CntOfPrFac[j]):10);
      inc(sum,CntOfPrFac[j]);
    end;
    writeln('sum: ',CommaUint(sum):10);
  writeln;
  sum := countOfPrimes+CountOfPrimePowers+1;
  writeln('For primes or powers (>1) there of <= ',CommaUint(LIMIT));
  Writeln('  Number of primes       =',CommaUint(countOfPrimes):8);
  Writeln('  Number of prime powers =',CommaUint(CountOfPrimePowers):8);
  Writeln('  Add 1 for number       =       1');
  Writeln('  sums to                =',CommaUint(sum):8);
  {$IFDEF WINDOWS}readln;{$ENDIF}
end.
@TIO.RUN:
The radicals for the first 50 positive integers are:
   1   2   3   2   5   6   7   2   3  10
  11   6  13  14  15   2  17   6  19  10
  21  22  23   6   5  26   3  14  29  30
  31   2  33  34  35   6  37  38  39  10
  41  42  43  22  15  46  47   6   7  10

Radical for   99,999:  33,333
Radical for  499,999:   3,937
Radical for  999,999: 111,111

Breakdown of numbers of distinct prime factors
for positive integers from 1 to 1,000,000
  1:     78,735
  2:    288,726
  3:    379,720
  4:    208,034
  5:     42,492
  6:      2,285
  7:          8
sum:  1,000,000

For primes or powers (>1) there of <= 1,000,000
  Number of primes       =  78,498
  Number of prime powers =     236
  Add 1 for number       =       1
  sums to                =  78,735

Real time: 0.560 s User time: 0.542 s Sys. time: 0.015 s CPU share: 99.40 %

Phix

with javascript_semantics
sequence radicals = reinstate(repeat(0,50),1,1),
         counts = reinstate(repeat(0,8),1,1)
for i=2 to 1e6 do
    sequence f = vslice(prime_powers(i),1)
    counts[length(f)] += 1
    if i<=50 then radicals[i] = product(f) end if
    if i=50 then
        printf(1,"The radicals for the first 50 positive integers are:\n%s\n",
                 {join_by(radicals,1,10," ",fmt:="%3d")})
    elsif i=99999 or i=499999 or i=999999 then
        printf(1,"Radical for %,7d: %,7d\n", {i, product(f)})
    elsif i=1e6 then
        printf(1,"\nBreakdown of numbers of distinct prime factors\n")
        printf(1,"for positive integers from 1 to 1,000,000:\n")
        for c=1 to 7 do
            printf(1,"  %d: %,8d\n", {c, counts[c]})
        end for
        printf(1,"    ---------\n")
        printf(1,"    %,8d\n\n", sum(counts))
    end if
end for
integer pcount = length(get_primes_le(1e6)),
       ppcount = 0
for p in get_primes_le(1000) do
    atom p2 = p
    while true do
        p2 *= p
        if p2>1e6 then exit end if
        ppcount += 1
    end while
end for
printf(1,"For primes or powers (>1) thereof <= 1,000,000:\n")
printf(1,"  Number of primes   = %,6d\n", pcount)
printf(1,"  Number of powers   = %,6d\n", ppcount)
printf(1,"  Add 1 for number 1 = %,6d\n", 1)
printf(1,"                       ------\n")
printf(1,"                       %,6d\n", pcount + ppcount + 1)

Output matches other entries (but w/o a charbarchart)

Raku

use Prime::Factor;
use List::Divvy;
use Lingua::EN::Numbers;

sub radical ($_) { [×] unique .&prime-factors }

say "First fifty radicals:\n" ~
  (1..50).map({.&radical}).batch(10)».fmt("%2d").join: "\n";
say '';

printf "Radical for %7s => %7s\n", .&comma, comma .&radical
  for 99999, 499999, 999999;

my %rad = 1 => 1;
my $limit = 1e6.Int;

%rad.push: $_ for (2..$limit).race(:1000batch).map: {(unique .&prime-factors).elems => $_};

say "\nRadical factor count breakdown, 1 through {comma $limit}:";
say .key ~ " => {comma +.value}" for sort %rad;

my @primes = (2..$limit).grep: &is-prime;

my int $powers;
@primes.&upto($limit.sqrt.floor).map: -> $p {
   for (2..*) { ($p ** $_) < $limit ?? ++$powers !! last }
}

say qq:to/RADICAL/;

    Up to {comma $limit}:
    Primes: {comma +@primes}
    Powers:    $powers
    Plus 1:      1
    Total:  {comma 1 + $powers + @primes}
    RADICAL
Output:
First fifty radicals:
 1  2  3  2  5  6  7  2  3 10
11  6 13 14 15  2 17  6 19 10
21 22 23  6  5 26  3 14 29 30
31  2 33 34 35  6 37 38 39 10
41 42 43 22 15 46 47  6  7 10

Radical for  99,999 =>  33,333
Radical for 499,999 =>   3,937
Radical for 999,999 => 111,111

Radical factor count breakdown, 1 through 1,000,000:
1 => 78,735
2 => 288,726
3 => 379,720
4 => 208,034
5 => 42,492
6 => 2,285
7 => 8

Up to 1,000,000:
Primes: 78,498
Powers:    236
Plus 1:      1
Total:  78,735

Wren

Library: Wren-math
Library: Wren-seq
Library: Wren-fmt
import "./math" for Int, Nums
import "./seq" for Lst
import "./fmt" for Fmt

var radicals = List.filled(51, 0)
radicals[1] = 1
var counts = List.filled(8, 0)
counts[1] = 1 
for (i in 2..1e6) {
    var factors = Lst.prune(Int.primeFactors(i))
    var fc = factors.count
    counts[fc] = counts[fc] + 1
    if (i <= 50) radicals[i] = Nums.prod(factors)
    if (i == 50) {
        System.print("The radicals for the first 50 positive integers are:")
        Fmt.tprint("$2d ", radicals.skip(1), 10)
        System.print()
    } else if (i == 99999 || i == 499999 || i == 999999) {
        Fmt.print("Radical for $,7d: $,7d", i, Nums.prod(factors))
    } else if (i == 1e6) {
        System.print("\nBreakdown of numbers of distinct prime factors")
        System.print("for positive integers from 1 to 1,000,000:")
        for (i in 1..7) {
            Fmt.print("  $d: $,8d", i, counts[i])
        }
        Fmt.print("    ---------")
        Fmt.print("    $,8d", Nums.sum(counts))
        Fmt.print("\nor graphically:")
        Nums.barChart("", 50, Nums.toStrings(1..7), counts[1..-1])
    }
}
var pcount = Int.primeCount(1e6)
var ppcount = 0
var primes1k = Int.primeSieve(1000)
for (p in primes1k) {
    var p2 = p
    while (true) { 
        p2 = p2 * p
        if (p2 > 1e6) break
        ppcount = ppcount + 1
    }
}
Fmt.print("\nFor primes or powers (>1) thereof <= 1,000,000:")
Fmt.print("  Number of primes   = $,6d", pcount)
Fmt.print("  Number of powers   = $,6d", ppcount)
Fmt.print("  Add 1 for number 1 = $,6d", 1)
Fmt.print("                       ------")
Fmt.print("                       $,6d", pcount + ppcount + 1)
Output:
The radicals for the first 50 positive integers are:
 1   2   3   2   5   6   7   2   3  10 
11   6  13  14  15   2  17   6  19  10 
21  22  23   6   5  26   3  14  29  30 
31   2  33  34  35   6  37  38  39  10 
41  42  43  22  15  46  47   6   7  10 

Radical for  99,999:  33,333
Radical for 499,999:   3,937
Radical for 999,999: 111,111

Breakdown of numbers of distinct prime factors
for positive integers from 1 to 1,000,000:
  1:   78,735
  2:  288,726
  3:  379,720
  4:  208,034
  5:   42,492
  6:    2,285
  7:        8
    ---------
    1,000,000

or graphically:

--------------------------------------------------
1 ■■■■■■■■ 78735
2 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 288726
3 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 379720
4 ■■■■■■■■■■■■■■■■■■■■■■ 208034
5 ■■■■ 42492
6 ◧ 2285
7 ◧ 8
--------------------------------------------------

For primes or powers (>1) thereof <= 1,000,000:
  Number of primes   = 78,498
  Number of powers   =    236
  Add 1 for number 1 =      1
                       ------
                       78,735