どのように私はJで慣用的にローランドプライムシーケンスを生成することができますか?
-
26-09-2019 - |
質問
あなたはローランドプライムシーケンスに慣れていない場合、あなたはそれを知ることができますこちらに。
:私は次の、最初ののnは、この順序での用語を生成するためにJに醜い、手続きモナド動詞を作成しましたrowland =: monad define result =. 0 $ 0 t =. 1 $ 7 while. (# result) < y do. a =. {: t n =. 1 + # t t =. t , a + n +. a d =. | -/ _2 {. t if. d > 1 do. result =. ~. result , d end. end. result )
これは完璧に動作し、それは確かにシーケンスの最初ののN の用語を生成します。
( N の観点から、私はのの別個のの素数N最初のを意味する。別)ここでrowland 20
の出力があります:
5 3 11 23 47 101 7 13 233 467 941 1889 3779 7559 15131 53 30323 60647 121403 242807
私の質問は、私は、リスト内の各連続した数の違いを見つけるために、次の関数を記述しなかったが、の私はより多くの慣用的なJ?の中でこれを書くことができますどのように私は、手掛かりを持っていない、あります必要なステップの一つである数字、の。それはあまりにもおそらく私よりも多くの経験を積んJプログラマがリファクタリングすることができるが、ここでは、次のとおりです。
diffs =: monad : '}: (|@-/@(2&{.) , $:@}.) ^: (1 < #) y'
解決
私は完全な答えを持っていない、まだ、しかしするロジャー・ホイによって明示的なのwhileループを置き換えるために使用することができます暗黙の構造を持っています。別の(関連)アベニューはそうのような暗黙式にブロックの内部ロジックを作成することであろう。
FUNWITHTACIT =: ] , {: + {: +. 1 + #
rowland =: monad define
result =. >a:
t =. 7x
while. (# result) < y do.
t =. FUNWITHTACIT t
d =. | -/ _2 {. t
result =. ~.result,((d>1)#d)
end.
result
)
(あなたは私がresult
は関係なく、条件が満たされたかどうかの変更されたような方法でコードを書いているので、効率化のためのブロック、しかし場合を維持することができます - 変更があり、それがなかった場合効果なし。if
ロジックをもアジェンダ演算子を使用して、暗黙の式に書き戻すことができる。)
の完全なソリューションは、単一の関数としてのwhileループ内のすべてのロジックを表し、そして次いで暗黙式としてながらロジックを実装するためにロジャーのトリックを使用する方法を見つけることから成ります。私は私が上げることができるかわかります。
はさておき、私は彼らが単一の引数上のすべてのオペレーティングたので手動で私は何ができる変数値(のために宣言された関数に代入し、あなたのコードの最初の数行を取ることによって私のためにビルドFUNWITHTACIT
にJを得たとしてさまざまな方法で)、t
でy
のすべてのインスタンスを置き換えると、得られた発現の暗黙の等価を構築するためにJを告げます:
]FUNWITHTACIT =: 13 : 'y,({:y)+(1+#y)+.({:y)'
] , {: + {: +. 1 + #
モナドを宣言するために13を使用すると、Jはモナドを取る(あなたがあなたのプログラムの中で書いたようにそれ以外の場合は、明示的に3 : 0
、またはmonad define
で宣言された)と暗黙の式に明示的な表現を変換するために知っている方法です。
EDITます:
ここで私は、私がコメントで述べていること大通り(2)のために書いた機能があります:
candfun =: 3 : '(] , {: + {: +. 1 + #)^:(y) 7'
firstdiff =: [: | 2 -/\ ]
triage =: [: /:~ [: ~. 1&~: # ]
rowland2 =: triage @firstdiff @candfun
この関数は、ローランド漸化式を用いて、第1のn多くの候補番号を生成する彼らの最初の差を評価し、破棄はすべて最初の違いは廃棄すべての重複、および昇順にソートして、1に等しいです。私は、引数は結果の番号の代わりにしようとする候補者の数を設定するので、それは、まだ完全には満足だとは思いません。しかし、それはまだ進行です。
例:
rowland2 1000
3 5 7 11 13 23 47 101 233 467 941
ここでは最小限に各引数のサイズを維持、私が掲示最初の関数のバージョンです。
NB. rowrec takes y=(n,an) where n is the index and a(n) is the
NB. nth member of the rowland candidate sequence. The base case
NB. is rowrec 1 7. The output is (n+1,a(n+1)).
rowrec =: (1 + {.) , }. + [: +./ 1 0 + ]
rowland3 =: 3 : 0
result =. >a:
t =. 1 7
while. y > #result do.
ts =. (<"1)2 2 $ t,rowrec t
fdiff =. |2-/\,>(}.&.>) ts
if. 1~:fdiff do.
result =. ~. result,fdiff
end.
t =. ,>}.ts
end.
/:~ result
)
昇順に第1のY多くの異なるローランド素数とプレゼントそれらを見つけ、
rowland3 20
3 5 7 11 13 23 47 53 101 233 467 941 1889 3779 7559 15131 30323 60647 121403 242807
この機能の複雑さの大部分は、箱入りの配列の私の扱いから来ています。それはかなりのコードはありませんが、それは唯一の計算中にメモリに(対数スケールで成長する)4+#result
多くのデータ要素を保持します。元の関数rowland
は(リニアスケール上に成長する)メモリで(#t)+(#result)
要素を保持します。 rowland2 y
は束縛指定を超えて、それが成長したことがないにもかかわらず、y
とほぼ同じそのメモリプロファイルを作るrowland
、多くの要素の配列を、構築します。多くのサイクルを使用してそのコンパクト用rowland2
のようなIが、式なしのn-多くの異なる素数を生成するために必要なy
の正確なサイズを予測するためには、そのタスクは、このように潜在的に試行錯誤で行われ、する必要があります冗長な計算上のrowland
またはrowland3
。 rowland3
は、すべてのループの繰り返しにrowland
再計算FUNWITHTACIT
いるので、おそらく#t
の私のバージョンよりも効率的である - rowland3
はちょうどあまり計算集約的であるカウンタをインクリメント
それでも、私はrowland3
の明示的な制御構造に満足していませんよ。再帰か何かを使って、この動作を実現する方法があるはずのように思えます。
他のヒント
、私はJとの長い、長い道のりを歩んできました。ここではJでローランドプライムシーケンスを生成するために、より多くの慣用的な方法があります:
~. (#~ 1&<) | 2 -/\ (, ({: + ({: +. >:@#)))^:(1000 - #) 7
表現(, ({: + ({: +. >:@#)))^:(1000 - #) 7
は、いわゆるの元のシーケンスの最大1000人のメンバーを生成します。このシーケンスの最初の相違は| 2 -/\
、すなわち、各2つの要素の差の絶対値によって生成することができます。 (元の質問から動詞私の元、長ったらしいdiffs
にこれを比較してください。)
最後に、私たちはものを削除し、重複した素数を素数のシーケンスを取得するために~. (#~ 1&<)
ます。
これは私が前にそれをやっていた方法に非常に優れています。簡単に少し再帰と素数のn
番号を生成するために、動詞に変換することができます。