7分割可能ルールを実装する


25

10進数が7で割り切れるかどうかを確認するには:

最後の桁を消去します。2で乗算し、残っているものから減算します。結果が7で割り切れる場合、元の数は7で割り切れます。

(例えばここにも説明されています

このルールは、手動の分割可能性チェックに適しています。例えば:

2016年は7で割り切れますか?

6*2201から減算します。189になります。これは7で割り切れますか?それを確認するために、もう一度ルールを適用しましょう。

9*218を引きます。したがって、2016は7で割り切れます。

このチャレンジでは、分割可能ステータスが明白になるまで、つまり、数が70以下になるまでこのルールを適用する必要があります(ただし、詳細については以下を参照してください)。関数または完全なプログラムを作成します。

入力:正の整数。コードは最大32767の入力をサポートする必要があります(任意精度の整数をサポートすることはボーナスです。以下を参照)。

出力:整数(おそらく負)、70以下。これは、7回の可分性ルールを0回以上適用した結果です。

テストケース:

Input                   Output      Alternative output

1                       1
10                      10          1
100                     10          1
13                      13          -5
42                      42          0
2016                    0
9                       9
99                      -9
9999                    -3
12345                   3
32767                   28          -14

---------- Values below are only relevant for the bonus

700168844221            70          7
36893488147419103232    32          -1
231584178474632390847141970017375815706539969331281128078915168015826259279872    8

2つの可能な出力が指定されている場合、どちらかの結果は正しいです。2番目の出力は、ルールをもう一度適用することに対応します。1桁の数字にルールを適用することは禁止されています。数字を消去すると、何も(0ではなく)残ります。


ボーナス:アルゴリズム

ここnで、10進数の桁数は次のとおりです。

コードのバイトカウントから50%を引きます。

リアルボーナス

さらに、アルゴリズムが最上位桁から開始して通常の方向で入力を読み取る場合、もう一度50%を引きます-スコアはバイトカウントの25%です(可能性があるようですが、確かではありません)。


1
@DenkerAffe入力をそのまま返すことは許容されます。これを反映するためにinput = 10のテストケースを更新しました。それが最初からのアイデアでした。
アナトリグ

4
私はそのルールをに使いたくありません1000000000000000000001
ニール

1
しかし、言語にlong longsまたは同等のタイプが組み込まれている場合はどうでしょうか?
SuperJedi224

1
私が言っていたのは、一部の実装では128ビット整数であり、その最後のテストケースには十分すぎるということでした。
SuperJedi224

7
-1。すべての言語が任意の精度をサポートしているわけではありません。
3月Ho

回答:


23

Golfscript、27 22バイト

{.9>{.10/\10%2*-f}*}:f

この方法で使用できます:

1000f

説明

{.9>{.10/\10%2*-f}*}:f
{                  }:f    # Define block 'f' (similar to a function)
 .                        # Duplicate the first value of the stack
  9>{            }*       # If the value on top of the stack is greater than 9 then the block is executed
     .10/\10%2*-          # Same as nb/10 - (nb%10 * 2) with some stack manipulations '.' to duplicate the top of the stack and '\' to swap the the first and second element of the stack
                f         # Execute block 'f'

Dennisのおかげで5バイト節約!


1
プログラミングパズルとコードゴルフへようこそ。これは良い答えですが、上記の質問のようにコードの詳細と説明を追加することで改善できます。このコメントに返信するには、コメントの先頭(またはコメント内の任意の場所)に@wizzwizz4@次にユーザー名)と入力します。
wizzwizz4

1
@ wizzwizz4ベター?私は確かに私はあなたが「コードブレークダウン」(ごめんないネイティブスピーカー)によって何を意味するかを理解することがないんだけど
ティップ

8
「コードの内訳」とは、彼が説明を意味していると思います。これは確かに非常に良い最初の答えです。サイトへようこそ!
アレックスA.

1
{...}{}ifとして書き換えることができ{...}*ます。これは、によってプッシュされた値に応じて、コードブロック0を1回だけ適用します>。また、もう1回反復を実行することが許可されているため(1 バイト709節約するために置き換えられます)、でブロックをポップする必要はないと思います;
デニス

3
@Dica、これは624ビューのみの質問に対して12以上の賛成票を獲得し、2人のモデレーターから賞賛を得るのに十分な最初の回答です。これを続ければ、すぐにデニスを追い越すでしょう!
wizzwizz4

13

Haskell、35バイト

until(<71)(\n->div n 10-2*mod n 10)

使用例:until(<71)(\n->div n 10-2*mod n 10) 36893488147419103232-> 32

説明することはあまりありませんが、これはアルゴリズムの直接的な実装です。


9

ゼリー、11バイト

d⁵Uḅ-2µ>9$¿

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

使い方

d⁵Uḅ-2µ>9$¿  Main link. Input: n

d⁵           Divmod; return [n : 10, n % 10].
  U          Upend; yield [n % 10, n : 10].
   ḅ-2       Convert from base -2 to integer, i.e., yield -2 × (n % 10) + (n : 10).

      µ      Push the previous chain as a link and begin a new, monadic chain.
          ¿  Apply the previous chain while...
       >9$     its return value is greater than 9.

そしていつものように、ゼリーが勝ちます。デニス、ゼリーにゼリーインタープリターを実装するにはどれくらいのバイトが必要ですか?
バリント

6

Python 2、38バイト

f=lambda x:f(x/10-x%10*2)if x>70else x

ここで試してみてください

単純な再帰的アプローチ。70未満の場合はxを出力し、それ以外の場合は分割可能性ルールを適用し、結果で自身を呼び出します。


後にスペースは必要ありません)
Maltysen

@Maltysenはい。間違ったコピーを貼り付けました、ヒントをありがとう!
デンカー

2
ifは冗長すぎます。f=lambda x:x*(x<70)or f(x/10-x%10*2)
seequ

1
@Seeq素敵なトリック、ありがとう!これは理論的には機能するはずですが、入力として2016で最大再帰深度に達しますが、私のバージョンではそうではありません。理由は何ですか?
デンカー

ああ、そうだね。このトリックx*(x<70) != 0は終了条件と見なされます。xが0に到達すると(2016の場合と同様)、終了条件は発生しません。
seequ

6

Pyth、13バイト

.W>H9-/ZTyeZQ

オンラインで試す:デモンストレーションまたはテストスイート

これにより、すべての代替回答が出力されます。

説明:

.W>H9-/ZTyeZQ   
            Q   read a number from input
.W              while
  >H9              the number is greater than 9
                do the following with the number:
      /ZT          divide it by 10
     -             and subtract
         yeZ       2*(number%10)

5

ジュリア、 27 26バイト

f(x)=x>9?f(x÷10-x%10*2):x

これは、整数を受け入れてを返す再帰関数ですBigInt。入力が最後の例のように大きな数値である場合、ジュリアはそれをとして解析するBigIntため、手動で変換する必要はありません。

このアプローチは、アルゴリズムの単純な実装です。代替出力が生成されます。10で除算するときにモジュラスを取ると、最後の桁が得られ、10で整数を除算した商は、最後の桁を除くすべてを返します。

デニスのおかげでバイトを節約できました!


もう1回反復を実行できるため、で置き換える7091バイト節約できます。
デニス

@Dennisよろしくお願いします!
アレックスA.

4

Pyth、17バイト

L?<b70by-/bT*%bT2

ここで試してみてください!

私のPythonの答えと同じ再帰的アプローチ。yこのように呼び出されるラムダを定義しますy12345
オンラインインタープリターのバイトカウンターには19バイトが表示されます。これは、ラムダ呼び出しを追加したためです。したがって、実行ボタンを押すだけで試すことができます。

説明

L?<b70by-/bT*%bT2

L                  # Defines the lambda y with the parameter b
 ?<b70             # if b < 70:
      b            # return b, else:
       -/bT*%bT2   # calculate b/10 - b%10*2 and return it

説明にタイプミスがあります
。17は

4

CJam-19バイト

暫定版:

r~A*{`)]:~~Y*-_9>}g

オンラインまたはWhileバージョン#1でお試しください

r~{_9>}{`)]:~~Y*-}w

オンラインまたはWhileバージョン#2で試してください

r~{_9>}{_A/\A%Y*-}w

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

r~                     | Read and convert input
  A*                   | Multiply by 10 to get around "if" rule
     `                 | Stringify
      )                | Split last character off
       ]               | Convert stack to array
        :~             | Foreach in array convert to value
          ~            | Dump array
           Y*          | Multiply by 2
             -         | Subtract
              _        | Duplicate
               9>      | Greater than 9?
    {            }g    | do-while

3

Oracle SQL 11.2、116バイト

WITH v(i)AS(SELECT:1 FROM DUAL UNION ALL SELECT TRUNC(i/10)-(i-TRUNC(i,-1))*2 FROM v WHERE i>70)SELECT MIN(i)FROM v;

ゴルフをしていない

WITH v(i) AS
(
  SELECT :1 FROM DUAL
  UNION ALL
  SELECT TRUNC(i/10)-(i-TRUNC(i,-1))*2 FROM v WHERE i>70
)
SELECT MIN(i) FROM v;

3

ハスケル、157の 192 184 167 159 147 138 + 5バイト- 50%= 71.5バイト

O(1)スペース、O(n)時間、シングルパス!

h d=d%mod d 10
d%r=(quot(r-d)10,r)
p![d]=d-p*10
p![d,e]=d#(e-p)
p!(d:e:f)|(b,a)<-quotRem(2*d)10,(q,r)<-h$e-a-p=(b+q)!(r:f)
m#0=m
m#n=n-2*m
(0!)

使用 0![6,1,0,2]をて、2016年にルールを適用します。つまり、最初に数字をストリーム形式で渡します。このようにして、O(1)空間の複雑さを持つルールを適用して、数字を1桁ずつ渡します。

改変されていないコードは次のとおりです。

import Data.Char

{- sub a b = sub2 0 a b
  where
    sub2 borrow (a:as) (b:bs) = res : sub2 borrow2 as bs
      where
        (borrow2, res) = subDig borrow a b
    sub2 borrow (a:as) [] = sub2 borrow (a:as) (0:[])
    sub2 _ [] _ = [] -}

--subDig :: Int -> Int -> Int -> (Int, Int)
subDig borrow a b = subDig2 (a - b - borrow)
  where
    subDig2 d = subDig3 d (d `mod` 10)
    subDig3 d r = ((r-d) `quot` 10, r)

seven ds = seven2 0 ds
seven2 borrow (d:e:f:gs) = seven2 (b + borrow2) (res:f:gs)
  where
    (a, b) = double d
    (borrow2, res) = subDig borrow e a
seven2 borrow (d:e:[]) = finalApp d (e-borrow)
seven2 borrow (d:[]) = d - borrow*10

double d = ((2*d) `mod` 10, (2*d) `quot` 10)

finalApp m 0 = m
finalApp m n = n - 2*m

num2stream :: Int -> [Int]
num2stream = reverse . map digitToInt . show
sev = seven . num2stream

この仕組みの要点は、桁ごとの減算アルゴリズムを実装することですごとのことですが、減算される各数値は最大2桁であるという事実を利用しているため、これらの任意の量を減算できますまたは、メインの数字から2桁の数字(および最下位の数字を食べる)。

減算アルゴリズムはO(1)であり、現在の「借入」値のみを保存します。これを変更して余分な数字(0または1)を追加し、この借用値が制限されていることに注意します(範囲[-2,2]内で、これを格納するのに必要なのは3ビットだけです)。

メモリに保存されている他の値は、追加する現在の2桁の数値、ストリーム内の単一の先読み、および減算アルゴリズムの1ステップを適用する一時変数です(つまり、2桁とボロー値を受け取り、 1桁と新しいボロー値)。

最後に、ストリームの最後の2桁を一度に処理して、数字のリストではなく1桁の数字を返します。

注意:sevungolfedバージョンの関数はで機能Integerし、逆ストリーム形式に変換します。


私はボーナスを通常の数字の順番にすることを意図していました。しかし、私はそれを言わなかったので、それは面白くはありませんが、逆順のボーナスを得るのは公平です。とにかく、逆順でも思ったより難しいので、十分に楽しいです!
アナトリグ

@anatolyg:ありがとう!通常の順序のシングルパスO(1)実装を行うことができるかどうかはわかりません...ルールは最下位の数字に依存するため、理論的には、逆の順序を除いてルールの直接適用は不可能です。私が考えることができる他の唯一のことは、数学的に同等の形式を見つけることです-例えばMod[18 - Quotient[n, 10] - 2*n, 21] - 18 + Quotient[n, 10]、10から99の間のnで経験的に動作しますが、nが多いほど複雑になります
ニトロ

うーん、私はそれについて考えて、前の2桁を保持し、後続の各桁を適用する方法があるかもしれないと思われましたが、(-2)^ nで乗算して「フィルタリング」を考慮します...メモリ内のすべての桁を維持し、Oを(1)「ネス、さらにはO(n)の」ネスを犠牲にすることなく、この作品を作るための方法はありませんけれども伝えることができます...私は、通常の順序は間違いなく不可能:(だと思う

1
0呼び出すときにイニシャルのバイトもカウントする必要があるのではないかと考えています!。たとえば、セクション(0!)(+改行)として、つまり+5バイトです。他の側では、あなたは、パターンマッチに最初短縮できる!p![d]=してp![d,e]=。また、let:の代わりにパターンガードを使用しますp!(d:e:f)|(b,a)<-quotRem(2*d)10,(q,r)<-h$e-a-p=(b+q)!(r:f)
nimi

1
@亜硝酸:ああ、私は(0!)それ自身の行に言及します。(0!)あなたが答えとして与える機能です。0必要な、しかし、あなたは、呼び出し元にそれを外部委託することはできませんので、入力とは何の関係もありません。もちろんを使用することもできますがf x=0!x、これはもっと長くなります。
nimi

3

GNU dc、20 15バイト

[10~2*-d70<F]sF

これにより、最初の(かつてない)DC関数が定義されますF。スタックの最上部で入力を受け取り、出力をスタックの最上部に残します。使用例:

36893488147419103232
lFxp
32

2

Mathematica、47 44バイト

If[#>70,#0[{1,-2}.{⌊#/10⌋,#~Mod~10}],#]&

単純な再帰的アプローチ。おそらくさらにゴルフすることができます。


#0[{1,-2}.QuotientRemainder[#,10]]バイトを保存します。
njpipeorgan

2

R、43バイト

x=scan();while(x>70)x=floor(x/10)-x%%10*2;x

説明:

x=scan()                                      # Takes input as a double
        ;                                     # Next line
         while(x>70)                          # While-loop that runs as long x > 70
                      floor(x/10)             # Divide x by 10 and round that down
                                 -x%%10*2     # Substract twice the last integer
                    x=                        # Update x
                                         ;    # Next line once x <= 70
                                          x   # Print x

サンプルの実行:

> x=scan();while(x>70)x=floor(x/10)-x%%10*2;x
1: 9999
2: 
Read 1 item
[1] -3

> x=scan();while(x>70)x=floor(x/10)-x%%10*2;x
1: 32767
2: 
Read 1 item
[1] 28

1

JavaScript ES6、38バイト

a=i=>i>70?a(Math.floor(i/10)-i%10*2):i

で失敗し36893488147419103232、使用~~(1/10)も失敗します700168844221

テスト:

a=i=>i>70?a(Math.floor(i/10)-i%10*2):i
O.textContent = O.textContent.replace(/(-?\d+) +(-?\d+)/g, (_,i,o) =>
  _+": "+(a(+i)==o?"OK":"Fail")
);
<pre id=O>1                       1
10                      10
100                     10
13                      13
42                      42
2016                    0
9                       9
99                      -9
9999                    -3
12345                   3
700168844221            70
36893488147419103232    32</pre>


私は2つの取得Fail秒... 70と32
コナー・オブライエン

@CᴏɴᴏʀO'Bʀɪᴇɴいや、まだ理由がわからない
...-andlrc

JavaScriptの数値型は少なくとも最後のケースを処理しないためです。
コナーオブライエン

1
f=n=>n>70?f((n-n%10*21)/10):nはより短いバージョンですが、それでも最大で動作し2**56ます。
ニール

@Neilは私の任意の精度についての答えを参照してください。
パトリックロバーツ

1

Mathematica、33バイト

#//.a_/;a>70:>⌊a/10⌋-2a~Mod~10&

テストケース

%[9999]
(* -3 *)

1

Perlの5、47の、46バイト

bigint最後のテストケースに使用する必要がありました。(なしで20を返します)

use bigint;$_=<>;while($_>9){$_-=2*chop;}print

それがボーナスの候補であるかどうかは確かではないので、私はそれを考慮しませんでした。(そうだと思うが、私は概念にあまり慣れていない)

ここで試してみてください!


1

ES6、108バイト

f=(s,n=0)=>s>1e9?f(s.slice(0,-1),((1+s.slice(-1)-n%10)%10*21+n-s.slice(-1))/10):s>9?f(((s-=n)-s%10*21)/10):s

2²⁵⁷および1000000000000000000001で動作しますが、さらにゴルフを使用できます。


@PatrickRobertsおっと、提出物の再フォーマット時の監視。
ニール

1

JavaScriptのES6、140の 142バイト

f=s=>s>9?eval("t=s.replace(/.$/,'-$&*2');for(i=-1;0>(n=eval(u=t[c='slice'](i-4)))&&u!=t;i--);n<0?n:f(t[c](0,i-4)+('0'.repeat(-i)+n)[c](i))"):s

これは真の任意精度の数学であり、最大のテストケースでも動作します。

この関数は、文字列から最後の桁を再帰的に削除し、差が正になるまで被減数に適用する桁数を繰り返し増分することにより、残りの数値文字列から最後の桁を2 *減算します。次に、適切にパディングされた0s を使用して文字列の末尾にその差を追加し、数値がより小さいか等しくなるまで再帰的に呼び出します9

  • @Neilのおかげで7バイトをゴルフしました(はい、私は2バイトを獲得したことを知っていますが、関数がフリーズしたり、場合によっては間違った出力を返すいくつかのバグを修正しました)。

f=s=>s>9?eval("t=s.replace(/.$/,'-$&*2');for(i=-1;0>(n=eval(u=t[c='slice'](i-4)))&&u!=t;i--);n<0?n:f(t[c](0,i-4)+('0'.repeat(-i)+n)[c](i))"):s;[['1',1],['10',1],['100',1],['13',-5],['42',0],['2016',0],['9',9],['99',-9],['9999',-3],['12345',3],['700168844221',7],['36893488147419103232',-1],['231584178474632390847141970017375815706539969331281128078915168015826259279872',8]].map(a=>document.write(`<pre>${f(a[0])==a[1]?'PASS':'FAIL'} ${a[0]}=>${a[1]}</pre>`))


いいですね、でも動作しないかもしれません1000000000000000000001
ニール

1
試してみてくださいs.replace(/.$/,'-$&*2')。申し訳ありませんが、残りのアイデアは明確ではありません。
ニール

1

C#、111 104バイト

int d(int n){var s=""+n;return n<71?n:d(int.Parse(s.Remove(s.Length-1))-int.Parse(""+s[s.Length-1])*2);}

1

Brain-Flak368 360バイト

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

([([({})]<(())>)](<>)){({}())<>}{}<>{}{}<>(({})){{}{}<>(<(())>)}{}({}<>){{}(({}))(<((()()()()()){}<>)>)<>{({}[()])<>(({}()[({})])){{}(<({}({}))>)}{}<>}{}<>([([([(({}<{}><>)<([{}]{})(<((()()()()()){}(<>))>)<>{({}[()])<>(({}()[({}<({}())>)])){{}(<({}({}<({}[()])>))>)}{}<>}{}<>{}{}({}<>)>){}]{})]<(())>)(<>)]){({}())<>}{}<>{}{}<>(({})){{}{}<>(<(())>)}{}({}<>)}{}

説明

すべてのコードを開始するには、スタックの最上位がゼロ未満になるまで実行されるループ内にあります。

([([({})]<(())>)](<>)){({}())<>}{}<>{}{}<>(({})){{}{}<>(<(())>)}{}({}<>)
{{}
 ...
 ([([({})]<(())>)](<>)){({}())<>}{}<>{}{}<>(({})){{}{}<>(<(())>)}{}({}<>)
}{}

ループ内で、7分割可能なアルゴリズムを実行します。

スタックの一番上を複製する

(({}))

スタックの最上位のmod 10を取得します(最後の桁)

(<((()()()()()){}<>)>)<>{({}[()])<>(({}()[({})])){{}(<({}({}))>)}{}<>}{}<>({}<{}><>)

これは少し混乱しますが、後で説明するかもしれない残りのアルゴリズムを実行しますが、それがどのように機能するかを完全に覚えていません:

([(({})<([{}]{})(<((()()()()()){}(<>))>)<>{({}[()])<>(({}()[({}<({}())>)])){{}(<({}({}<({}[()])>))>)}{}<>}{}<>{}{}({}<>)>){}]{})

1

C、56バイト-75%= 14

これはテストケースと正確に同じ数を与えるものではありませんが、質問の精神を満たします(ほぼ間違いなく)。7の正確な倍数を正しく識別し、他の数値の正確な剰余を与えます(負の数値を使用しないため)。

n;f(char*c){for(n=0;*c;)n-=n>6?7:'0'-n-n-*c++;return n;}

アルゴリズムには乗算または除算はなく、加算と減算のみがあり、数字は左から右への単一パスで処理されます。アキュムレータの0から始まる次のように機能します。

  1. 必要に応じて7を引き、さらに必要であれば再び引きます
  2. 実行中の合計に3を掛け、次の数字を追加します

「3で乗算」ステップはn-=-n-n、バイトを保存し、乗算演算子を回避するために記述されています。

最後に達すると、7を減算しないため、結果は0〜24の範囲になります。厳密なモジュラス(0〜7)が必要な場合は、ループ条件で置換*cします。*c||n>6for

それは強化されたボーナスの資格があります。

  • 任意精度の整数をサポート
  • 入力に対して左から右の順序で1つのパスのみを実行します
  • スペースの複雑さO(1)
  • 時間の複雑さはO(n)です。

テストプログラムと結果

#include <stdio.h>
int main(int argc, char **argv) {
    while (*++argv)
        printf("%s -> %d\n", *argv, f(*argv));
    return 0;
}
540 -> 15
541 -> 16
542 -> 17
543 -> 18
544 -> 19
545 -> 20
546 -> 21
547 -> 22
548 -> 23
549 -> 24
550 -> 18
99 -> 15
999 -> 12
12345 -> 11
32767 -> 7
700168844221 -> 7
36893488147419103232 -> 11
231584178474632390847141970017375815706539969331281128078915168015826259279872 -> 11

代替バージョン

ここでは再帰的には(あなたは末尾呼び出しの変換を行うには、コンパイラの最適化を可能にしたいと思うか、あなたのスタックがオーバーフローする可能性があり、私が使用することを一つですgcc -std=c89 -O3):

f(c,n)char*c;{return n>6?f(c,n-7):*c?f(c+1,n+n+n+*c-'0'):n;}

2番目の引数として「0」で呼び出します。

どちらのバージョンも、私のマシンで50ミリ秒未満で60,000桁の剰余モジュロセブンを計算します。


ボーナスをお寄せいただきありがとうございます。Cが非常に競争力のあるものになるように、Cに大きな変化をもたらします。現在、Jelly(11)とPyth(13)だけにbeatられています。:
トビー・スペイト

1

PHP、50バイト

for($n=$argv[1];$n>9;)$n=$n/10|0-2*($n%10);echo$n;

代替出力を使用します。まで働くPHP_INT_MAX


文字列バージョン、任意の(正の)数(64バイト)で機能します。

for($n=$argv[1];$n>9;)$n=substr($n,0,-1)-2*substr($n,-1);echo$n;

0

Java、133バイト

int d(int n){String s=""+n;return n<71?n:d(Integer.parseInt(s.replaceFirst(".$",""))-Integer.parseInt(""+s.charAt(s.length()-1))*2);}

冗長性Integer.parseIntが嫌いです。ゴルフをしていない:

static int div(int n) {
    if (n <= 70) {
        return n;
    } else {
        String num = ("" + n);
        int last = Integer.parseInt("" + num.charAt(num.length() - 1));
        int k = Integer.parseInt(num.replaceFirst(".$", "")) - last * 2;
        return div(k);
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.