オイラーのtotient関数を計算する


27

バックグラウンド

オイラーのtotient 関数φ(n)は、にn素数であるかそれ以下の整数の数n、つまりxin 0 < x <= nforの 可能な値の数として定義されますgcd(n, x) == 1。私たちは持っていた いくつかのトーティエント - 関連の課題 の前に、ちょうどそれを計算していることはありません1。

totient関数の整数へのマッピングはOEIS A000010です。

チャレンジ

整数を指定してn > 0、計算しφ(n)ます。コマンドライン引数、標準入力、関数引数、またはその他の妥当なものを使用して入力を取得できます。標準出力、戻り値、またはその他の妥当なものを使用して出力することができます。匿名関数は受け入れ可能です。入力はint、Cなどの整数を格納する自然な方法をオーバーフローさせないと仮定することができますが、255までの入力をサポート する必要があります

φ(1) => 1
φ(2) => 1
φ(3) => 2
φ(8) => 4
φ(9) => 6
φ(26) => 12
φ(44) => 20
φ(105) => 48

バイト単位の最短回答が優先されます。あなたの言語がUTF-8以外のエンコーディングを使用している場合は、回答でそれを言及してください。


4
さて、先日これがありました。繰り返し適用しても十分な違いがあるとは思いませんが、もう一方を閉じるとしたら、繰り返し適用しても何も追加されないと思います。とはいえ、大きな違いは、ビルトインを許可するものと許可しないものです。
マーティンエンダー

ビルトインを拒否しても、回答に影響はありません。
ジュリーペレティエ

2
@JuliePelletierそれはなぜですか?私のMathematicaの答えは、そうでない場合は19バイトより短くされているでしょう:EulerPhi
マーティン・エンダーを

@JuliePelletier GCDは許可されています。GCDの計算は、解決すべき問題ではないためです。確かに、これらの回答のバイト数を増やす可能性がありますが、チャレンジを改善するものではありません。明確にするために編集します。
bkul

回答:


13

Mathematica、27 22バイト

Range@#~GCD~#~Count~1&

整数を受け取って返す名前のない関数。

ここで説明することはあまりありませんが、それ@は関数呼び出しのプレフィックス表記であり、~...~(左結合)インフィックス表記であるため、上記は同じです:

Count[GCD[Range[#], #], 1] &

11

MATL、7バイト

t:Zd1=s

TryItOnlineを実行できます。最も簡単なアイデアは、ベクトルを1からNにし、Nで各要素のgcdを取得します(gcdを実行しますZd)。次に、どの要素が1に等しいかを見つけ、ベクトルを合計して答えを取得します。


組み込みは_Zp不思議な人向けです。
デビッド

9

J、9バイト

(-~:)&.q:

これは、Jsoftwareのtotient関数に関するエッセイに基づいています。

所与のN = P 1 、E 1P 2 E 2 ∙∙∙ P K のE K Pのkはの素因数であるN、トーティエント関数φ(N)=φ(P 1 E 1)∙φ(P 2 、Eは2)∙∙∙φ(P k個のE 、K)=(P 1 - 1)P 1 、E 1 - 1 ∙(P 2 - 1)、P 2E 2 - 1 ∙∙∙( PのK - 1) Pのk個のEのK - 1

使用法

   f =: (-~:)&.q:
   (,.f"0) 1 2 3 8 9 26 44 105
  1  1
  2  1
  3  2
  8  4
  9  6
 26 12
 44 20
105 48
   f 12345
6576

説明

(-~:)&.q:  Input: integer n
       q:  Prime decomposition. Get the prime factors whose product is n
(   )&     Operate on them
  ~:         Nub-sieve. Create a mask where 1 is the first occurrence
             of a unique value and 0 elsewhere
 -           Subtract elementwise between the prime factors and the mask
     &.q:  Perform the inverse of prime decomposition (Product of the values)

totientが乗法であるという事実を使用して、再帰を使用してJで別のソリューションを作成します:)
リーキー修道士

@LeakyNun繰り返し形式を使用しても[:*/@({.(^-(^<:)){:)2&p:24バイトが必要であり、組み込み関数を使用して素数とその指数を取得するため、ファクタリングをゴルフする簡単な方法はないと思います。または、もっと短い方法があり、私はそれを見ません。
マイル


7

Haskell、28バイト

f n=sum[1|1<-gcd n<$>[1..n]]

Haskellの定数パターンマッチングを使用します。ここでのコツはゴルフのかなり標準的なものですが、一般の聴衆に説明します。

式はにgcd n<$>[1..n]マッピングgcd nされ[1..n]ます。つまり、to からの各数値のgcdwith nを計算1nます:

[gcd n i|i<-[1..n]]

ここから、望ましい出力は1エントリの数ですが、Haskellにはcount機能がありません。filterのみを保持し1、結果を取得する慣用的な方法lengthは、ゴルフには長すぎます。

代わりに、結果のリストを使用filterしたリスト内包によってシミュレートされ[1|1<-l]ますl。通常、リスト内包表記はinのように変数に値をバインドします[x*x|x<-l]が、Haskellではパターン(この場合はconstant)を照合できます1

したがって、の各一致でを[1|1<-l]生成すると、元のリストののみが効果的に抽出されます。それを呼び出すと、その長さがわかります。111sum


これは私が実際に理解している最初のHaskellの答えだと思います。とてもクールな言語ですが、他のほとんどの言語とは大きく異なります。
bkul

うわー、私は理解リストでパターンマッチングが網羅的でなければならないと思っていました。トリックをありがとう。
ダミアン


6

Python 2、44バイト

f=lambda n,d=1:d/n or-f(d)*(n%d<1)-~f(n,d+1)

少ないゴルフ:

f=lambda n:n-sum(f(d)for d in range(1,n)if n%d<1)

の約数のオイラー積算n値の和がn次の式を使用します。

enter image description here

の値は、自明でない除数の合計からマイナスϕ(n)として再帰的に計算できnます。事実上、これは恒等関数でメビウス反転を行っています。ゴルフでも同じ方法を使用して、メビウス関数を計算しました

より良いベースケースで1バイトを保存+n+1、各nループのに初期値を拡散してくれたDennisに感謝します-~


5

Python> = 3.5、76 64 58バイト

12(!)バイトのゴルフをしてくれたLeakyNunに感謝します。

6バイトのゴルフをしてくれたSp3000に感謝します。

import math
lambda n:sum(math.gcd(n,x)<2for x in range(n))

Pythonの読みやすさが大好きです。これは、ゴルフをしていても意味があります。


1
lambda n:sum(gcd(n,x)<2for x in range(n))
リーキー修道女

ああ、ついにPython gcdがmathモジュールに追加されました!知りませんでした。
ルービック

5

正規表現(ECMAScript)、131バイト

Deadcode(チャット)のおかげで少なくとも-12バイト

(?=((xx+)(?=\2+$)|x+)+)(?=((x*?)(?=\1*$)(?=(\4xx+?)(\5*(?!(xx+)\7+$)\5)?$)(?=((x*)(?=\5\9*$)x)(\8*)$)x*(?=(?=\5$)\1|\5\10)x)+)\10|x

オンラインでお試しください!

出力は一致の長さです。

ECMAScriptの正規表現は、数を数えることを非常に困難にします。ループの外部で定義されたbackrefはループ中は一定であり、ループの内部で定義されたbackrefはループ時にリセットされます。したがって、ループの反復間で状態を保持する唯一の方法は、現在の一致位置を使用することです。それは単一の整数であり、減少することしかできません(まあ、位置は増加しますが、尾の長さは減少します。

これらの制限があるため、単純に素数を数えることは不可能に思えます。代わりに、オイラーの公式を使用してトーティエントを計算します。

擬似コードでは次のようになります。

N = input
Z = largest prime factor of N
P = 0

do:
   P = smallest number > P that’s a prime factor of N
   N = N - (N / P)
while P != Z

return N

これには2つの疑わしい点があります。

まず、入力を保存せず、現在の製品のみを保存します。それでは、入力の素因数にどのようにアクセスできますか?秘Theは、(N-(N / P))がNと同じ素因数を持っていることです。新しい素因数<Pを獲得するかもしれませんが、とにかくそれらを無視します。これが機能するのは、最小から最大まで素因数を反復するためだけであり、他の方法では失敗することに注意してください。

第二に、ループの繰り返し全体で2つの数値を覚えておく必要があります(PとN、Zは定数であるためカウントされません)。ありがたいことに、これら2つの数値を1つの数値に切り替えることができます。ループの開始時に、Nは常にZの倍数になり、Pは常にZ未満になることに注意してください。したがって、N + Pを記憶し、モジュロでPを抽出できます。

次に、もう少し詳細な擬似コードを示します。

N = input
Z = largest prime factor of N

do:
   P = N % Z
   N = N - P
   P = smallest number > P that’s a prime factor of N
   N = N - (N / P) + P
while P != Z

return N - Z

そして、コメント付きの正規表現は次のとおりです。

# \1 = largest prime factor of N
# Computed by repeatedly dividing N by its smallest factor
(?= ( (xx+) (?=\2+$) | x+ )+ )

(?=
        # Main loop!
        (
                # \4 = N % \1, N -= \4
                (x*?) (?=\1*$)

                # \5 = next prime factor of N
                (?= (\4xx+?) (\5* (?!(xx+)\7+$) \5)? $ )

                # \8 = N / \5, \9 = \8 - 1, \10 = N - \8
                (?= ((x*) (?=\5\9*$) x) (\8*) $ )

                x*
                (?=
                        # if \5 = \1, break.
                        (?=\5$) \1
                |
                        # else, N = (\5 - 1) + (N - B)
                        \5\10
                )
                x
        )+
) \10

ボーナスとして…

正規表現(ECMAScript 2018、一致数)、23バイト

x(?<!^\1*(?=\1*$)(x+x))

オンラインでお試しください!

出力は一致の数です。ECMAScript 2018では、可変長の後読み(右から左に評価)が導入されました。これにより、入力と互いに素なすべての数を単純にカウントすることができます。

これは、独立してLeaky NunのRetinaソリューションで使用されているのと同じ方法であり、正規表現は同じ長さ(および交換可能)でさえあることがわかります。このメソッドがECMAScript 2018(.NETだけでなく)で動作するのは興味深いかもしれないので、ここに残しておきます。

                        # Implicitly iterate from the input to 0
x                       # Don’t match 0
 (?<!                 ) # Match iff there is no...
                 (x+x)  # integer >= 2...
         (?=\1*$)       # that divides the current number...
     ^\1*               # and also divides the input

4

Perl 6の 26の24  22バイト

{[+] (^$^n Xgcd $n) X== 1}
{+grep 2>*,(^$_ Xgcd$_)}
{[+] 2 X>(^$_ Xgcd$_)}

説明:

{
  [+] # reduce using &infix:<+>
    2
    X[>] # crossed compared using &infix:«>»
    (
      ^$_    # up to the input ( excludes input )
      X[gcd] # crossed using &infix:<gcd>
      $_     # the input
    )
}

例:

#! /usr/bin/env perl6
use v6.c;

my  = {[+] 2 X>(^$_ Xgcd$_)};

say φ(1) # 1
say φ(2) # 1
say φ(3) # 2
say φ(8) # 4
say φ(9) # 6
say φ(26) # 12
say φ(44) # 20
say φ(105) # 48

say φ 12345 # 6576


4

J、11バイト

+/@(1=+.)i.

使用法

>> f =: +/@(1=+.)i.
>> f 44
<< 20

どこ>>STDINであり、<<STDOUTです。

説明

+/ @ ( 1 = +. ) i.
               │
   ┌───────────┴┐
 +/@(1=+.)      i.
   │
 ┌─┼──┐
+/ @ 1=+.
    ┌─┼─┐
    1 = +.

>> (i.) 44            NB. generate range
<< 0 1 2 3 4 ... 43
>> (+.i.) 44          NB. calculate gcd of each with input
<< 44 1 2 1 4 ... 1
>> ((1=+.)i.) 44      NB. then test if each is one (1 if yes, 0 if no)
<< 0 1 0 1 0 ... 1
>> (+/@(1=+.)i.) 44   NB. sum of all the tests
<< 20

どのようにして垂直ツリー表現を取得しましたか?私はそれが水平のみを生成すると思った。
マイル

@miles私は自分で入力しました。
リーキー修道女

4

ジュリア、25バイト

!n=sum(i->gcd(i,n)<2,1:n)

それは簡単です-このsum関数は、加算する前に適用する関数を与えることができます-基本的にはrunning mapとthenに相当しsumます。これは、を下回る比較的素数の数を直接カウントしnます。


4

Python 2、57バイト

f=lambda n,k=1,m=1:n*(k>n)or f(n-(n%k<m%k)*n/k,k+1,m*k*k)

テストする Ideoneでます。

バックグラウンド

オイラーの積公式により、

Euler's product formula

ここで、φはオイラーのトーティエント関数を表し、pは素数でのみ変化します。

素数を識別するために、ウィルソンの定理の帰納法を使用します。

corollary of Wilson's theorem

使い方

常に、変数mk-1の階乗の二乗に等しくなります。実際、引数にデフォルトでk = 1およびm = 0を指定しました!2 = 1

長いほどK≤N n*(k>n)に評価0とコード次or実行されます。

リコールm%k得られます1場合、mが素数であると0でない場合。つまり、kが素数でxkで割り切れる場合にのみTruex%k<m%kを生成します

この場合、(n%k<m%k)*n/k収量N / K、及びからそれを差し引くNとのその前の値置き換えN - (1 / k)はオイラーの製品式のように、。それ以外の場合、(n%k<m%k)*n/kyields 0およびnは変更されません。

上記を計算した後、kをインクリメントし、mk 2の「古い」値を乗算します。したがって、kmの間の望ましい関係を維持し、fを呼び出します。更新引数で再帰。

一度kが超えるNn*(k>n)と評価nは関数によって返されます。


3

Brachylog、25バイト

:{:1e.$pdL,?$pd:LcCdC}fl.

説明

BrachylogにはまだGCDが組み込まれていないため、2つの数値に共通の素因数がないことを確認します。

  • 主な述語:

    :{...}fl.             Find all variables which satisfy predicate 1 when given to it as
                          output and with Input as input.
                          Unify the Output with the length of the resulting list
    
  • 述語1:

    :1e.                  Unify Output with a number between Input and 1
        $pdL              L is the list of prime factors of Output with no duplicates
            ,
             ?$pd:LcC     C is the concatenation of the list of prime factors of Input with
                          no duplicates and of L
                     dC   C with duplicates removed is still C
    


3

PowerShell v2 +、72バイト

param($n)1..$n|%{$a=$_;$b=$n;while($b){$a,$b=$b,($a%$b)};$o+=!($a-1)};$o

PowerShellにはGCD機能がありませんので、自分でロールバックする必要がありました。

これは入力を受け取り$n1to からtoの範囲で$nループします|%{...}。各繰り返しは、我々は2つのヘルパー変数を設定$aし、$bその後、GCDの実行whileループを。私たちがチェックしている各反復$bはまだゼロではないので、次のループのために$a%$bto $bとto の前の値を保存します。次に、出力変数に等しいかどうかを蓄積します。forループが完了したら、$b$a$a1$o$oすると、パイプラインにれ、出力が暗黙的になります。

whileループがどのように機能するかの例として、考慮$n=20してください$_=8。最初のチェックにはが$b=20あるため、ループに入ります。$a%$bまたはを計算します8%20 = 8。これは、に設定さ$bれると同時に20設定され$aます。を確認し8=0、2番目の反復を入力します。次に、それを計算20%8 = 4してに設定し$b、に設定$a8ます。を確認し4=0、3番目の反復を入力します。それを計算8%4 = 0して設定します$b、次にに設定$a4ます。チェック0=0してループを終了します。GCD(8,20)$a = 4です。したがって、!($a-1) = !(4-1) = !(3) = 0そのように$o += 0カウントしません。


3

ルビー、32バイト

->n{(1..n).count{|i|i.gcd(n)<2}}

整数nを取り、範囲(1..n)でnと互いに素である整数の数のカウントを返すラムダ。


こんにちは、PPCGへようこそ!これは素晴らしい最初の投稿です。
-NoOneIsHere

プログラミングパズルとコードゴルフへようこそ!これは素晴らしい最初の解決策です、それを維持してください!
-bkul

おかげで、それほど短くはありませんが、改善できるかどうか疑問に思います。
Redouaneレッド


2

網膜、36 29バイト

Martin Enderのおかげで7バイト。

.+
$*
(?!(11+)\1*$(?<=^\1+)).

オンラインでお試しください!

説明

2つの段階(コマンド)があります。

第一段階

.+
$*

これは単純な正規表現の置換であり、入力をその多くのものに変換します。

たとえば、5に変換され11111ます。

第2段

(?!(11+)\1*$(?<=^\1+)).

この正規表現は、条件を満たす入力(入力とのプライム)を一致させてから、一致の数を返します。


先読みは、先読み内でない限りバックトラックしませんか?
リーキー修道女

ルックアラウンドは一般的に後戻りしません。
マーティンエンダー

次に、正規表現がすべての除数をテストしたのはどうですか?
リーキー修道女

1
あなたがそれらを残さない限り、まあ彼ら後戻りします。エンジンがルックアラウンド内にある限り、そのルックアラウンドを一致させるために可能な限りすべてを試みます(または、ネガティブルックアラウンドの場合は失敗します)。ただし、ルックアラウンドが渡されると、エンジンは、障害が発生した後に何かに戻ってもバックトラックしません(その後、ルックアラウンドので物事をバックトラックし始め、とにかくすべてを再評価する必要がある場合を除く)。
マーティンエンダー

2

Common Lisp、58バイト

(defun o(x)(loop for i from 1 to x if (=(gcd x i)1)sum 1))

これは、1を指定されたnまでカウントし、gcd = 1の場合に合計をインクリメントする単純なループです。tは真のブール値であるため、関数名oを使用します。最短ではありませんが、かなりシンプルです。


CLには何らかの匿名関数がありませんか?

2

MATLAB /オクターブ、21バイト

@(n)sum(gcd(n,1:n)<2)

ans整数nを唯一の入力として呼び出すことができるという名前の匿名関数を作成します。ans(n)

オンラインデモ


2

係数、50バイト

[ dup iota swap '[ _ gcd nip 1 = ] filter length ]

範囲(せるイオタN、及びカレー N取得関数にGCD XNのすべての値について0 <= X <= nの結果である場合、テスト1gcd xnの結果が1であったかどうかについて元の範囲をフィルタリングし、その長さを取得します。


[ dup iota swap '[ _ gcd nip 1 = ] map sum ]6バイトを節約します(私は思う-Factorにあまり慣れていません)。
bkul

@bkul提案をありがとう!:D残念ながら、t/fFactorの数字と(記号)には互換性がないため、それを実装する唯一の方法[ dup iota swap '[ _ gcd nip 1 = 1 0 ? ] map sum ]は、現在のソリューションと同じ正確な長さです。

ああ、ダン。強いタイピングが再び発生します。
bkul

@bkulまあ、私は強い型付けのためと感謝TYPED:本当の要因コード:P



1

実際には、11バイト

;╗R`╜g`M1@c

オンラインでお試しください!

説明

;╗R`╜g`M1@c   register stack             remarks

                       44
;                      44 44
 ╗            44       44
  R           44       [1 2 3 .. 44]
       M      44       10                for example
    ╜         44       10 44
     g        44       2
              44       [1 2 1 .. 44]     gcd of each with register
        1     44       [1 2 1 .. 44] 1
         @    44       1 [1 2 1 .. 44]
          c   44       20                count

ビルトイン

オンラインでお試しください!


あなたは、代わりに使用することができ;╗R`╜g1=`MΣ、同じバイト数のために
MEGO

1

JavaScript(ES6)、67バイト

f=n=>[...Array(n)].reduce(r=>r+=g(n,++i)<2,i=0,g=(a,b)=>b?g(b,a%b):a)



1

Haskell、31 30バイト

\n->sum[1|x<-[1..n],gcd n x<2]

@Damienのおかげで1バイトが節約されました。

gcd = 1の値を選択し、それぞれを1にマップしてから、合計を取ります。


あなたは置き換えることができます==1<2
ダミアン

1

バッチ、151 145 144バイト

@echo off
set t=
for /l %%i in (1,1,%1)do call:g %1 %%i
echo %t%
exit/b
:g
set/ag=%1%%%2
if not %g%==0 call:g %2 %g%
if %2%==1 set/at+=1

編集:不要なスペースを削除して4バイトを保存しました。を使用して1バイトを保存しました+=。とにかくそれを解釈するようにクリアtする+=ことによって1バイトを保存しまし0た。@EʀɪᴋᴛʜᴇGᴏʟғᴇʀのおかげで1バイト節約されました。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.