1

ローランド素数列に慣れていない場合は、ここで調べることができます。次のように、このシーケンスの最初のn項を生成するために、J で醜い手続き型単項動詞を作成しました。

rowland =: モナドの定義
    結果=。0 $ 0
    t =。1 $ 7
    その間。(# 結果) < そうです。
        =。{:t
        n =。1 + # トン
        t =。t、a + n +。a
        d =。| | -/ _2 {. t
        もしも。d > 1 です。
            結果=。〜。結果、d
        終わり。
    終わり。
    結果
)

これは完全に機能し、実際にシーケンスの最初の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 でどのように書くことができるかということです。手がかりはありませんが、次の関数を作成して、必要な手順の 1 つである、数字のリスト内の連続する数字の違いを見つけました。これは、おそらく私よりも経験豊富な J プログラマーによってリファクタリングされる可能性がありますが、次のとおりです。

diffs =: モナド: '}: (|@-/@(2&{.) , $:@}.) ^: (1 < #) y'
4

2 に答える 2

3

私はすでにエスタンフォードの答えを正しいものとしてマークしていますが、この質問をして以来、Jとは長い道のりを歩んできました。J でローランド素数列を生成する、より慣用的な方法を次に示します。

~. (#~ 1&<) | 2 -/\ (, ({: + ({: +. >:@#)))^:(1000 - #) 7

この式は、最大 1000 メンバー(, ({: + ({: +. >:@#)))^:(1000 - #) 7のいわゆるオリジナル シーケンスを生成します。この数列の最初の差分は| 2 -/\、つまり 2 つの要素ごとの差分の絶対値によって生成できます。(これを、元の質問の元の長いdiffs動詞と比較してください。)

最後に、1 つと重複する素数を削除して、~. (#~ 1&<)素数のシーケンスを取得します。

これは、私が以前に行っていた方法よりもはるかに優れています。n少しの再帰で素数の数を生成する動詞に簡単に変えることができます。

于 2012-02-20T17:05:24.730 に答える
2

完全な答えはまだありませんが、 Roger Hui によるこのエッセイには、明示的な 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 ブロックを保持したい場合があります。満たされていない場合、変更は効果がありません。 ifAgenda 演算子を使用して、ロジックを暗黙の式に書き戻すこともできます。)

完全な解決策は、while ループ内のすべてのロジックを 1 つの関数として表現する方法を見つけてから、ロジャーのトリックを使用して while ロジックを暗黙の式として実装することです。何ができるか見てみます。

余談FUNWITHTACITですが、コードの最初の数行を取り、宣言した変数値の関数を手動で置き換えることで、J をビルドしてもらいました (これらはすべて単一の引数でさまざまな方法で操作されていたため、これを行うことができました)。のすべてのインスタンスをtwithに置き換え、yJ に結果の式の暗黙の等価物を構築するように指示しました。

]FUNWITHTACIT =: 13 : 'y,({:y)+(1+#y)+.({:y)'
   ] , {: + {: +. 1 + #

モナドを宣言するために 13 を使用することは、J がモナドを取り (それ以外の場合は で明示的に宣言する3 : 0monad define、プログラムで記述したように)、明示的な式を暗黙的な式に変換する方法を知っている方法です。

編集:

コメントで言及したアベニュー(2)用に書いた関数は次のとおりです。

candfun =: 3 : '(] , {: + {: +. 1 + #)^:(y) 7'
firstdiff =: [: | 2 -/\ ]
triage =: [: /:~ [: ~. 1&~: # ]
rowland2 =: triage @firstdiff @candfun

この関数は、Rowland 再帰関係を使用して最初の 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
) 

最初の 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-many 要素の配列を構築します。これにより、メモリ プロファイルは、指定された境界を超えて大きくならない場合yとほぼ同じになります。rowlandrowland2はそのコンパクトさを気に入っていyますが、 n 個の異なる素数を生成するために必要な の正確なサイズを予測する式がなければ、そのタスクは試行錯誤に基づいて実行する必要があり、したがって、rowlandまたはrowland3よりも多くのサイクルを使用する可能性があります。冗長な計算。rowland3は、ループの反復ごとに再計算するrowlandため、私のバージョンの よりもおそらく効率的です。カウンターをインクリメントするだけで、計算量が少なくなります。FUNWITHTACIT#trowland3

それでも、私はrowland3の明示的な制御構造には満足していません。再帰などを使用してこの動作を実現する方法があるはずです。

于 2010-06-12T13:10:42.070 に答える