challenge 正整数のゲーデル数化?

正の整数 n を引数としてとり, 2^d1 * 3^d2 * 5^d3 ... * pk^dk を返す関数
goedel を定義してください.

ただし,n を10進表現で k 桁の数としたときの各桁の数が数列 [d1,d2,d3,...,dk]
をなすとし,dk が 1 の位,d1 が 10^(k-1) の位です.また,pk は k番目の素数です.

goedel   9  ⇒ 2^9             ⇒  512
goedel  81  ⇒ 2^8 * 3^1       ⇒  768
goedel 230  ⇒ 2^2 * 3^3 * 5^0 ⇒  108

Posted feedbacks - Perl

もうちょっと簡単に出来そう

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
use strict;
use warnings;
use Math::Prime::XS qw(is_prime);
use List::Util qw(reduce);
use List::MoreUtils qw(pairwise);

sub primes {
    my $number = shift;
    my @primes = (2);
    my $i      = 3;
    while ( @primes < $number ) {
        push( @primes, $i ) if is_prime($i);
        $i++;
    }
    return @primes;
}

sub goedel {
    my $number = shift;
    my @num    = split //, $number;
    my @primes = primes( scalar(@num) );
    reduce { $a * $b } pairwise { $a**$b } @primes, @num;
}

print goedel(9);
print goedel(81);
print goedel(230);

goedel_number()の二番目の引数にnonzeroを指定することで#4657で指摘した「仕様バグ」にも対応しています。

Dan the Goedel Numberer

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#!/usr/local/bin/perl
use strict;
use warnings;

my @primes = ( 2, 3 );

sub fill_primes {
    my $nprimes = shift;
  ODD:
    for ( my $n = $primes[ @primes - 1 ] + 2 ; @primes < $nprimes ; $n += 2 ) {
        for my $d (@primes) {
            last if $d * $d > $n;
            next ODD unless $n % $d;
        }
        push @primes, $n;
    }
}

sub goedel_number {
    my $n      = shift;
    my $offset = shift || 0;
    my @d      = ( $n =~ /(\d)/g );
    fill_primes( scalar @d );
    use bigint;
    my $result = 1;
    $result *= $primes[$_]**( $d[$_] + $offset ) for ( 0 .. @d - 1 );
    $result;
}

local $\ = "\n";
local $, = ", ";
print goedel_number( $ARGV[0] || 1234567890, $ARGV[1] );

Index

Feed

Other

Link

Pathtraq

loading...