バウンスモジュロ2数


12

モジュロ演算のグラフ()は次のようになります。y=xmodk

Graph of the modulo function

これは、「ラッピング」動作を作成できるため、非常に便利な機能です。ただし、2つの壁の間で「バウンス」のような外観を作成するために使用する場合、非常に面倒です。「バウンス」関数のグラフ()は次のようになります。y=bounce(x,k)

Graph of the "bounce-modulo" function

y = xのグラフの期間 kです。y = バウンスx k のグラフの周期は 2 kです。これは、 k単位で上方に移動し、さらに k単位で下方に移動してから、開始位置に戻るためです。両方の関数について、 yの最小値は0、最大値は kです(実際、積分入力のモジュラス関数の場合、 k 1です)。また、両方の関数で、 x = 0の値は0です。y=xmodkky=bounce(x,k)2kkkykk1x=0

チャレンジ

整数と正の整数kを指定するとy = bounce x k )の整数または浮動小数点近似を返します。xky=bounce(x,k)

これはであるため、最短の有効な送信(バイト単位)が勝ちます。

テストケース

  x,  k -> bounce(x, k)
  0, 14 ->            0
  3,  7 ->            3
 14, 14 ->           14
 15, 14 ->           13
-13, 14 ->           13 (12.999997 etc would be an acceptable answer)
-14, 14 ->           14
191,  8 ->            1
192,  8 ->            0

以下のためのボーナスポイントフーリエ変換にアプローチをベースフーリエ変換


" 両方の関数で、xの最小値は0で、最大値はkです。
ピーターテイラー

@PeterTaylorおっと。結果を意味します。
エソランジングフルーツ

1
おっと、それは私がすでに言ったと思ったことです。まだ間違っています。k % k = 0
ピーターテイラー

@PeterTaylorああ、私はあなたの質問を理解しています。私はもともと浮動小数点を念頭に置いてこれを設計していましたが、その後、単なる整数に切り替えました。編集します。
エソランジングフルーツ

1
@PeterTaylor引数がfloatの場合、最大値はに任意に近い数kです。
エソランジングフルーツ

回答:


7

x86-64マシンコード、18バイト

97
99
31 D0
29 D0
99
F7 FE
29 D6
A8 01
0F 45 D6
92
C3 

このコードは、計算するx86-64マシン言語の関数を定義しますbounce(x, k。Gnu / Unixシステムで使用されるSystem V AMD64呼び出し規約に従って、xパラメーターはEDIレジスターにk渡され、パラメーターはESIレジスターに渡されます。すべてのx86呼び出し規約と同様に、結果はEAXレジスタに返されます。

これをCから呼び出すには、次のようにプロトタイプを作成します。

int Bounce(int x, int k);

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

非ゴルフアセンブリニーモニック:

; Take absolute value of input 'x' (passed in EDI register).
; (Compensates for the fact that IDIV on x86 returns a remainder with the dividend's sign,
; whereas we want 'modulo' behavior---the result should be positive.)
xchg   eax, edi      ; swap EDI and EAX (put 'x' in EAX)
cdq                  ; sign-extend EAX to EDX:EAX, effectively putting sign bit in EDX
xor    eax, edx      ; EAX ^= EDX
sub    eax, edx      ; EAX -= EDX

; Divide EDX:EAX by 'k' (passed in ESI register).
; The quotient will be in EAX, and the remainder will be in EDX.
; (We know that EAX is positive here, so we'd normally just zero EDX before division,
; but XOR is 2 bytes whereas CDQ is 1 byte, so it wins out.)
cdq
idiv   esi

; Pre-emptively subtract the remainder (EDX) from 'k' (ESI),
; leaving result in ESI. We'll either use this below, or ignore it.
sub    esi, edx

; Test the LSB of the quotient to see if it is an even number (i.e., divisible by 2).
; If not (quotient is odd), then we want to use ESI, so put it in EDX.
; Otherwise (quotient is even), leave EDX alone.
test   al, 1
cmovnz edx, esi

; Finally, swap EDX and EAX to get the return value in EAX.
xchg   eax, edx
ret

最初のセクション(絶対値を取る)は、同等に記述できた可能性があります。

; Alternative implementation of absolute value
xchg    eax, edi
neg     eax
cmovl   eax, edi

これはまったく同じバイト数です(6)。パフォーマンスは似ているはずで、おそらくわずかに高速です(条件付きの移動が遅い特定のIntelチップを除く)。

XCHGもちろん、比較的低速でありMOV、コードゴルフ(オペランドの1つがアキュムレータである場合は前者が1バイトであるのに対し、レジスタとレジスタMOVは常に2バイトである)を除いては優先されません。


6

ゼリー、3バイト

æ%A

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

組み込みのftw。

説明

æ%ここに便利なビルトインです。私はそれを記述する方法がわからないので、いくつかの入力に出力を提供します。

通りxから行く0無限大に、xæ%4行く0,1,2,3,4,(-3,-2,-1,0,1,2,3,4,)括弧内の部分は、両方の方法無限に繰り返されます。




3

ルビー、40バイト 32バイト

b=->(x,k){(x/k+1)%2>0?x%k:k-x%k}

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

説明

こんにちは、このサイトでの最初の回答です!このコードは、(n -1)k <= x < nkでnが奇数の場合、バウンス関数はモジュロのように動作し、nが偶数の場合は逆モジュロ演算のように動作するという観察に基づいています。 x / k(整数に切り捨てられたx / k +1)(x/k+1)よりも大きい最小の整数です。したがって、上記のnを見つけます。 nが奇数か偶数かを確認します。もしN > 0 MOD 2、次いでN奇数です。nの場合(x/k+1)%2>0mod 2 = 0の場合、nは偶数です。nが奇数の場合、バウンス関数はx mod kに等しくなければなりません。場合nは偶数である、バウンス機能が逆でなければならない、に等しいK - X MOD K。式全体(x/k+1)%2>0?x%k:k-x%knを見つけ、それが奇数であればx mod kを実行し、そうでなければk - x mod kを実行します。

答えは、Cyoceからの提案に基づいて改善されました


これをラムダに変換できます。def b(x,k) ... end使用の代わりに->x,k{...}
チョイス

そして、整数を扱って.to_iいるので、必要ありません。
チョイス



1

J、25バイト

ヒント:

これは、ラダー番号の通常のモジュロです。たとえば、5の場合:0 1 2 3 4 5 4 3 2 1

これがJの(まだよくできていない)ソリューションです。明日改善しようとします。

[ ((|~ #) { ]) (i.@>:,}:@i.@-) @ ]

圧縮された: [((|~#){])(i.@>:,}:@i.@-)@]

圧縮2: [((|~#){])(<:|.|@}.@i:)@]

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


i:ここで使用できるように感じますが、まだ解決策を試していません
コナーオブライエン

@ ConorO'Brienは私のcompress2バージョンをチェックアウトし、を使用して数バイトを節約しますi:。メインのものを更新し、説明を提供する時間がありませんでした。少なくとも4〜5バイトは専門家が削ることができると思います
ジョナ

((|~#){])]-|@}:@i:18バイト
マイル

@miles beautiful、tyvm-
ジョナ

1

QBIC25 30 27バイト

g=abs(:%:)~a'\`b%2|?b-g\?g

少し再編しました...

説明

g=abs(   )  let g be the absolute value of 
       %    the (regular) modulo between
      : :   input a read from cmd line, and input b read from cmd line
~a \ b%2    IF the int division of A and B mod 2 (ie parity test) yields ODD
  ' `         (int divisions need to be passed to QBasic as code literals, or ELSE...)
|?b-g       THEN print bouncy mod
\?g         ELSE print regular mod

QBICは、MOD操作に対して他のBasic実装とは異なることを行いますか?他の基本は、配当と同じ符号でMODを返します。そのときは失敗しx-13で、k14ある
コーディグレー

@CodyGrayいや、それは-13を与えた。修正されました。
-steenbergh

あなたはabs両方の時間を必要としませんか?
ニール

@Neilのテストケースはありますか?
-steenbergh

@Neil nvm、全体を再構築することで修正しました。
-steenbergh

1

C89、40バイト

t;f(x,k){t=abs(x%k);return x/k%2?k-t:t;}

私のx86マシンコードの ACポートは、これを定義します。これはf、パラメータxおよびのバウンス係数を計算する関数kです。

C89のimplicit-intルールを使用しているため、両方のパラメーター、グローバル変数t、および関数の戻り値はすべて暗黙的にtypeになりintます。グローバル変数tは一時的な値を保持するためにのみ使用され、条件演算子の両側で計算を繰り返すのと比較して、最終的にバイトを節約します。

abs関数(絶対値)が設けられている<stdlib.h>ヘッダが、我々は再びここで、(関数は、暗黙的に宣言して返すと仮定されるC89の暗黙のintルールのおかげで、それを含める必要はありませんint)。

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

ゴルフされていないバージョン:

#include <stdlib.h>

int Bounce(int x, int k)
{
    int mod = abs(x % k);
    return (x/k % 2) ? k-mod : mod;
}

私の手作業で調整されたマシンコードに照らしてこれを見ると、コンパイラは実際にかなり良い出力生成します。つまり、彼らはそうすべきです。最適化するのは非常に簡単な関数です!私はGCCのx86-64のオプティマイザではマイナーなバグ発見、それは不思議作り出すところ、しかし、より大きなコードを、あなたはサイズのために最適化し、それを教えてくれたときに小さなあなたのために最適化するためにそれを伝える時にコードの速度


m;f(x,k){m=abs(x%k);x=x/k%2?k-m:m;}短い
-user41805

x86ターゲット上のGCCコードジェネレーターの動作が原因で、特定の不明確な状況を除いて、実際に値@cowsを返さないことを除きます。これは人々がここで使用するテンプレートですが、私にとってはうまくいきません。たまたまスタックからランダムなゴミを取り出して、それがたまたま正しい答えになっているだけです。
コーディグレー

1

Haskell、37バイト

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

(!)=mod;x#k|odd$x`div`k=k-x!k|1<2=x!k

使用方法:
コールとして15#14非負左引数のとして(-13)#14負の左引数の、Haskellは解釈するため-13#14として-(13#14)、あなたのようなものを使用している場合ghci。TIOリンクは、単純に2つのコマンドライン引数を取ります。

説明:
最初に、2項中置演算子!をと同じに再定義しmodます。Haskellはmod常に非負の値を出力するため、必要ありませんabsここでの他のソリューションでません。次に、x/k(整数除算)が奇数かどうかをチェックし、奇数の場合はk-x mod k(バックバウンスなど)を返すか、そうでない場合はを返しますx mod k


これはおそらく、単なる好みの問題ですが、私は個人的に定義しないことを好む!、それは上の任意のバイトは保存されませんので、x#k|odd$x`div`k=k-x`mod`k|1<2=x`mod`k
マーク・S

1

PHP、40 50バイト

いまいましいドル。インポートのオーバーヘッドを気にします。:)

整数バージョン:

[,$x,$k]=$argv;$y=abs($x)%$k;echo$x/$k&1?$k-$y:$y;

または

[,$x,$k]=$argv;echo[$y=abs($x)%$k,$k-$y][$x/$k&1];

floatバージョン、56バイト:

交換してくださいabs($x)%$kfmod(abs($x),$k)


編集:負の結果を修正 x


4
「くそドル」。ええ、お金は悪臭を
放ち

2
どの程度€argv£argv?それらは素敵に見えるだろう:x
イスマエルミゲル

1

JavaScript(ES6)、 36 32バイト

k=>f=x=>x<0?f(-x):x>k?k-f(k-x):x

xに対して再帰的にバウンドします。これは非常にチャレンジ精神に基づいています。0k




0

R、28バイト

pryr::f(abs((x-k)%%(2*k)-k))

関数に評価する:

function (k, x) 
abs((x - k)%%(2 * k) - k)

これは、ほとんどのソリューションで使用されている方法のようです。これを作る前にそれらを見なかった。

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