裏 RjpWiki

Julia ときどき R, Python によるコンピュータプログラム,コンピュータ・サイエンス,統計学

Julia で,ベクトル要素の全てと互いに素である整数のリストを求める

2021年08月21日 | ブログラミング

お題

ベクトル要素のそれぞれと互いに素である整数のリストを求める

ベクトル a の全ての要素との gcd(最大公約数)が 1(つまり,互いに素)である m 以下の整数を列挙する。
例えば,
a = [4, 6] で,m = 20 のとき
a に含まれる数の約数は,2, 3 の2個
1 〜 20 までの数のうち,
2 で割りきれるものは,題意を満たさない(gcd は 2)。題意を満たすのは 1,3,5,7,9,11,13,15,17,19 の 10 個
そのうち,3 で割りきれるものは,題意を満たさない(gcd は 3)。題意を満たすのは 1, 5, 7, 11, 13, 17, 19 の 7 個

エラトステネスの篩と同じ考え方

1 〜 m の集合の内,既存の数の倍数(a の各要素の約数の集合)を全部潰していって,残ったのが解の集合ということ。

# 約数の候補
function divisor(n)
    n % 2 == 0 && return 2
    maxitr = floor(Int, sqrt(n))
    for i = 3:2:maxitr
        n % i == 0 && return i
    end
    n
end

# 約数の集合
function factorization(n)
    result = []
    while n > 1
        div = divisor(n)
        append!(result, div)
        while n % div == 0
            n ÷= div
        end
    end
    result
end

# どの約数でも割りきれない数を残す
function f(n, m, a)
    set = Set()
    for i in a
        union!(set, Set(factorization(i)))
    end
    lengthofset = length(set)
    intvector = trues(m)
    for i in set
        maxindex = m ÷ i
        for j = 1:maxindex
            intvector[j*i] = false
        end
    end
    println(sum(intvector .== true))
    for (i, element) in enumerate(intvector)
        if element
            println(i)
        end
    end
end

a = [4, 6]
m = 20

f(length(a), m, a)
#=
7
1
5
7
11
13
17
19
=#

コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

ひねくれ者のプログラマー(追記あり)

2021年08月21日 | ブログラミング

普通に書いたら何の面白味もないので,ひねくれた書き方をしてみる。

追記:何点か(たくさん)修正しました(赤字の部分)。2021/08/26

お題

整数値をとる引数が,1〜125 なら 1,126〜211 なら 2,212〜214 なら 3 を返す関数を定義せよ。

まともな解答??

function f1(N::Int64)
    if 1 <= N <= 125
        return 1
    elseif 126 <= N <= 211
        return 2
    elseif 212 <= N <= 214
        return 3

    else
        return "error"
    end
end

f1(215) # "error" という文字列を返す
f1(3.5) # Julia から "MethodError: no method matching f1(::Float64)" を返す

ひねくれ者の解答

1〜214  のときに返す値のベクトルを用意しておいて,整数引数を添え字として値を返す。
添え字範囲を超えると Julia が  BoundsError を返す

function f2(N::Int64)
    return vcat(fill(1, 125), fill(2, 86), fill(3, 3))[N]
end

一行で書くならば,

f3(N::Int64) = vcat(fill(1, 125), fill(2, 86), fill(3, 3))[N]

多項式近似して

f4(N::Int64) = round(Int, sum([1.15683106318897e+00, -3.85131039015425e-02, 2.25503374685424e-03, -5.10900952943894e-05, 5.19543217094899e-07, -2.36769347431069e-09, 3.95939127643363e-12] .* (N.^(0:6))))

というのもありか。

追記

中澤さんからのコメントで,新たなアルゴリズムが提示されました。
Rだと
f5 <- function(N) { (N %/% 1 > 0) + (N %/% 126 > 0) + (N %/% 211 > 0) }

それに基づいて,なるべくちゃんとした結果を返す Julia プログラムを書いてみました。

f5(N::Int) =  0 < N < 215 ? 1 + (N ÷ 126 > 0) + (N ÷ 212 > 0) : "error"

f5(1)   # 1
f5(125) # 1
f5(126) # 2
f5(211) # 2
f5(212) # 3
f5(214) # 3
f5(215) # "error"
f5(1.3) # MethodError
f5(0)   # "error"
f5(-1)  # "error"

ちゃんとした結果を返すプログラムを書くのは,けっこう大変ですね。

コメント (3)
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

PVアクセスランキング にほんブログ村

PVアクセスランキング にほんブログ村