ブラックボックス三角法


29

以下の12個の三角関数を区別できるプログラムや関数を書きます: sincostanasinacosatansinhcoshtanhasinhacoshatanh

プログラムには上記の関数のいずれかがブラックボックスとして与えられ、上記の関数名または言語での名前の付け方のいずれかで関数名を出力する必要があります。

これはであるため、各言語で最も短い回答が優先されます。12個の入力すべてにテストケースを含めることで、コードが正しく機能することを示す必要があります。選択した言語に上記のすべての機能の組み込みが含まれていない場合は、欠落しているものの独自の賢明な実装を提供する必要があります。

さらなる説明

  • 基礎となるビルドインが複素数を処理できる場合は、複素数を使用してブラックボックスを照会できます。
  • のみ実数を使用する場合、ブラックボックス機能へのクエリは、ドメインエラーを与えることができます。この場合、ブラックボックスはエラーの存在のみを伝え、エラーの発生元は伝えないと想定する必要があります。dom acoshdom atanh=
  • エラーの代わりに、他の値、たとえば、NaNまたはnullが返された場合、送信でそれらを処理できる必要があります。

有益なサンドボックスフィードバックをありがとう!


1
Mathematicaはシンボリック入力を処理できるので、関数出力が部分的にしか評価されない場合があります。違いは、計算の代わりにパターンマッチングを使用できることです。
ジョンファンミン

1
@JungHwanMinこれは、シンボリック出力から関数名にアクセスできることを意味する場合、許可されていないことを恐れています。
ライコニ

回答:


22

Linux上のPython 3.6.4、99バイト

ちょっと馬鹿げた答えですが、

lambda f:"asinh acos cos cosh atan atanh tan sin asin tanh sinh acosh".split()[hash(f(.029))%19%12]

cmath複雑な入出力のために、三角関数が組み込みモジュールの1つである必要があります。


2
@JungHwanMin私はあなたが混乱していると信じています。私は確かに実際の機能を取ります。入力への唯一の参照ff(.029)、値を指定して関数を呼び出すことです。
orlp

1
これをブルートフォースしましたか?
mbomb007

4
@ mbomb007総当たりで言うと、まばたきで数百回の繰り返しを行うループを意味します。
orlp

3
これは驚くべきことです。
NIT


6

Perl 6、75バイト

->&f {([X~] ("","a"),<sin cos tan>,("","h")).min({abs(f(2i)-&::($_)(2i))})}

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

たまたま、区別される関数の12個すべてが組み込みであり、すべてが複雑な引数を取ります。

[X~] ("", "a"), <sin cos tan>, ("", "h")クロス積連結を使用して3つの入力リストを削減することにより、12個すべての関数名を生成します。それらが与えられると.min(...)、入力関数との差が最も小さいものを見つけ2iます。


59バイト Xは複数の用語に使用でき、ゴルフバイトへのいくつかの他のトリック
ジョーキング

6

C(gcc)178 172バイト

double d;_;f(double(*x)(double)){d=x(0.9247);_=*(int*)&d%12;puts((char*[]){"acosh","sinh","asinh","atanh","tan","cosh","asin","sin","cos","atan","tanh","acos"}[_<0?-_:_]);}

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

古くてかっこいい:C(gcc)、194バイト

double d;_;f(double(*x)(double)){char n[]="asinhacoshatanh";d=x(0.9247);_=*(int*)&d%12;_=(_<0?-_:_);n[(int[]){10,5,5,0,14,10,4,4,9,14,0,9}[_]]=0;puts(n+(int[]){5,1,0,10,11,6,0,1,6,10,11,5}[_]);}

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

-lmTIO の切り替えは、単にテストすることです。 標準のトリガー関数の完全な実装を作成できれば、正しい答えが得られます。

説明

アイデアは、各トリガー関数の出力を整数として解釈するときに、12を法とする剰余が異なるような入力値を見つけることでした。これにより、配列インデックスとして使用できるようになります。

このような入力値を見つけるために、次のスニペットを作成しました。

#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>

// Names of trig functions
char *names[12] = {"sin","cos","tan","asin","acos","atan","sinh","cosh","tanh","asinh","acosh","atanh"};

// Pre-computed values of trig functions
double data[12] = {0};

#define ABS(X) ((X) > 0 ? (X) : -(X))

// Performs the "interpret as abs int and modulo by" operation on x and i
int tmod(double x, int i) {
    return ABS((*(int*)&x)%i);
}

// Tests whether m produces unique divisors of each trig function
// If it does, it returns m, otherwise it returns -1
int test(int m) {
    int i,j;
    int h[12] = {0}; // stores the modulos

    // Load the values
    for (i = 0; i < 12; ++i)
        h[i] = tmod(data[i],m);

    // Check for duplicates
    for (i = 0; i < 12; ++i)
        for (j = 0; j < i; ++j)
            if (h[i] == h[j])
                return -1;

    return m;
}

// Prints a nicely formatted table of results
#define TEST(val,i) printf("Value: %9f\n\tsin      \tcos      \ttan      \n  \t%9f\t%9f\t%9f\na \t%9f\t%9f\t%9f\n h\t%9f\t%9f\t%9f\nah\t%9f\t%9f\t%9f\n\n\tsin      \tcos      \ttan      \n  \t%9d\t%9d\t%9d\na \t%9d\t%9d\t%9d\n h\t%9d\t%9d\t%9d\nah\t%9d\t%9d\t%9d\n\n",\
        val,\
        sin(val), cos(val), tan(val), \
        asin(val), acos(val), atan(val),\
        sinh(val), cosh(val), tanh(val),\
        asinh(val), acosh(val), atanh(val),\
        tmod(sin(val),i), tmod(cos(val),i), tmod(tan(val),i), \
        tmod(asin(val),i), tmod(acos(val),i), tmod(atan(val),i),\
        tmod(sinh(val),i), tmod(cosh(val),i), tmod(tanh(val),i),\
        tmod(asinh(val),i), tmod(acosh(val),i), tmod(atanh(val),i))

// Initializes the data array to the trig functions evaluated at val
void initdata(double val) {
    data[0] = sin(val);
    data[1] = cos(val);
    data[2] = tan(val);
    data[3] = asin(val);
    data[4] = acos(val);
    data[5] = atan(val);
    data[6] = sinh(val);
    data[7] = cosh(val);
    data[8] = tanh(val);
    data[9] = asinh(val);
    data[10] = acosh(val);
    data[11] = atanh(val);
}

int main(int argc, char *argv[]) {
    srand(time(0));

    // Loop until we only get 0->11
    for (;;) {
        // Generate a random double near 1.0 but less than it
        // (experimentally this produced good results)
        double val = 1.0 - ((double)(((rand()%1000)+1)))/10000.0;
        initdata(val);
        int i = 0;
        int m;

        // Find the smallest m that works
        do {
            m = test(++i);
        } while (m < 0 && i < 15);

        // We got there!
        if (m == 12) {
            TEST(val,m);
            break;
        }
    }

    return 0;
}

これを実行すると(-lmでコンパイルする必要があります)、値が0.9247の場合に一意の値が得られます。

次に、整数として再インターペットし、12を法として適用し、絶対値を取りました。これにより、各関数にインデックスが与えられました。それらは(0-> 11):acosh、sinh、asinh、atanh、tan、cosh、asin、sin、cos、atan、tanh、acosです。

これで、文字列の配列にインデックスを付けることができましたが、名前は非常に長く、非常に似ているため、代わりに文字列のスライスからそれらを取り出します。

これを行うには、文字列「asinhacoshatanh」と2つの配列を作成します。最初の配列は、文字列内のどの文字をヌルターミネータに設定するかを示し、2番目の配列は、文字列内のどの文字を最初の文字にするかを示します。これらの配列には、10,5,5,0,14,10,4,4,9,14,0,9および5,1,0,10,11,6,0,1,6,10,11が含まれます。それぞれ5。

最後に、Cで再解釈アルゴリズムを効率的に実装するだけでした。残念なことに、double型を使用する必要がありました。正確に3 double回使用すると、3回使用#define D double\nDDD してから2文字だけ使用する方が速くなりました。結果は上にあり、説明は下にあります。

double d;_;                                 // declare d as a double and _ as an int
f(double(*x)(double)){                      // f takes a function from double to double
    char n[]="asinhacoshatanh";             // n is the string we will manipulate
    int a[]={10,5,5,0,14,10,4,4,9,14,0,9};  // a is the truncation index
    int b[]={5,1,0,10,11,6,0,1,6,10,11,5};  // b is the start index
    d=x(0.9247);                            // d is the value of x at 0.9247
    _=*(int*)&d%12;                         // _ is the remainder of reinterpreting d as an int and dividing by 12
    _=(_<0?-_:_);                           // make _ non-negative
    n[a[_]]=0;                              // truncate the string
    puts(n+b[_]);}                          // print the string starting from the correct location

編集:残念ながら、生の配列を使用するだけで実際には短くなるため、コードははるかに単純になります。それにもかかわらず、文字列のスライスは楽しかったです。理論的には、適切な議論は実際にいくつかの数学で適切なスライスを思い付くかもしれません。


あなたは置き換えることにより、20のバイトを保存することができputs(...)printf("%.5s","acoshsinh asinhatanhtan cosh asin sin cos atan tanh acos "+5*(_<0?-_:_))
カーティス・ベクテル

コード内の-DD=doubleすべてdoubleのをでコンパイルして置き換えると、5バイト節約できますD。フラグは合計バイトに対してカウントする必要があることに注意してください。

に置き換えchar*[]int*[]、三項演算子(?:)をabs(_)

6

Linuxでは、上のPython 3.6.5 90 85のバイト

h=hash;lambda f:h(f(.0869))%3%2*"a"+"tscaionns"[h(f(.14864))%3::3]+h(f(.511))%5%2*"h"

これはorlpの答えに基づいています。しかし、マジック番号を1つ見つける代わりに、3つ見つけます!これは基本的に、「sin」、「cos」、および「tan」の文字列リテラルを複数回配置することを避け、バイトを節約し、代わりに一度に1つずつ答えを作成します。

最初のマジック番号は、「arc」三角関数の1つであるかどうかを判断するために使用され、それに応じて「a」が付加され、2番目は「sin」、「cos」、適切な文字列、およびそれが双曲線関数の1つであるかどうかの3番目、それに応じて「h」を追加します。

orlpの答えと同様に、Pythonの組み込みcmathモジュールの関数を入力として使用します。

中央の文字列にスライスインデックスを使用して5バイトを節約しました

マジックナンバーを見つける

完全を期すために、これらのマジックナンバーを見つけるために使用したスクリプトを(多かれ少なかれ)ここに示します。私は主にpythonターミナルでまっすぐ作業しただけなので、コードは乱雑ですが、仕事は完了しています。

import cmath
fns = [(fn, getattr(cmath, fn)) for fn in ["sin","cos","tan","asin","acos","atan","sinh","cosh","tanh","asinh","acosh","atanh"]]

count_length = lambda num, modulus, base_modulus : len(str(num).rstrip('0').lstrip('0')) + (1 + len(str(modulus)) if modulus != base_modulus else 0)

min_length = float("inf")
min_choice = None
for modulus in range(2,10):
   for i in range(1,100000):
      num = i/100000.
      is_valid = True
      for fn in fns:
         val = hash(fn[1](num))%modulus%2
         if (val == 0 and fn[0][0]=="a") or (val == 1 and fn[0][0]!="a"):
            is_valid = False
      if is_valid:
         length = count_length(num, modulus, 2)
         if length < min_length:
            min_length = length
            min_choice = (modulus,num)
print(min_choice)

min_length = float("inf")
min_choice = None
for modulus in range(3,10):
   for i in range(100000):
      num = i/100000.
      mapping = {}
      is_valid = True
      for fn in fns:
         fn_type = "sin" if "sin" in fn[0] else "cos" if "cos" in fn[0] else "tan"
         val = hash(fn[1](num))%modulus%3
         if val in mapping and mapping[val] != fn_type:
            is_valid = False
            break
         mapping[val] = fn_type
      if is_valid:
         length = count_length(num, modulus, 3)
         if length < min_length:
            min_length = length
            min_choice = (modulus, num, mapping)
print(min_choice)

min_length = float("inf")
min_choice = None
for modulus in range(2,10):
   for i in range(1,100000):
      num = i/100000.
      is_valid = True
      for fn in fns:
         val = hash(fn[1](num))%modulus%2
         if (val == 0 and fn[0][-1]=="a") or (val == 1 and fn[0][-1]!="a"):
            is_valid = False
      if is_valid:
         length = count_length(num, modulus, 2)
         if length < min_length:
            min_length = length
            min_choice = (modulus,num)
print(min_choice)

1
素晴らしい第二の答え!マジックナンバーの検索に使用したプログラムを共有してもらえますか?
mbomb007

ありがとう!魔法の数字を見つけるためのコードを答えに追加しましたが、それほどきれいではありません。
nthistle

4

Python108 94 90バイト

入力関数の結果をvalueのすべての関数の結果と比較します.2

from cmath import*
lambda f:[w for w in globals()if w[-1]in'shn'and eval(w)(.2)==f(.2)][0]

オンラインで試す

ジョナサンアレンによる-14バイトロッド
による-4バイト


必要はありませんre。ただスライスして必要なものを取得し、lambda f,d=dir(cmath):[s for s in d[4:12]+d[22:]if eval("cmath."+s)(.2)==f(.2)][0](インポートの前に行われる必要がありますようTIO上の仕事に書き換えd=dir(cmath)、まだF=カウントされないように、ヘッダ内になければなりません)。
ジョナサンアラン


非常に素晴らしい!ありがとう
mbomb007

4

Dyalog APL25 21 19バイト

(8-(2○⍨8-⍳15)⍳⎕2)∘○

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

-3おかげH.PWiz
-2おかげNGN

必要なすべてのtrig関数(APLでは1 2 3 5 6 7 ¯1 ¯2 ¯3 ¯5 ¯6 ¯7○2)とさらにいくつか(これはtrough -7..7)を行き来し、どれが一致するかを見つけinput○2、その「with」を出力します。num∘○


3

C(GCC)-lm374の 346 324バイト

提案してくれたGiacomo Garabelloに感謝します。

文字列化を行う元のマクロに加えて、ヘルパーマクロにトークン貼り付けを実行させることで、スペースをもう少し節約できました。

テストでは、いくつかの非ライブラリトリガー関数を使用して、結果の妥当性を確認しました。ライブラリー関数と非ライブラリー関数の間の結果はまったく同じ浮動小数点値ではなかったため、等式を使用する代わりに、結果の差を小さな値εと比較しました。

#include <math.h>
#define q(f)f,#f,
#define _(f,g)q(f##sin##g)q(f##cos##g)q(f##tan##g)
#define p for(i=0;i<24;i+=2)
typedef double(*z)(double);*y[]={_(,)_(a,)_(,h)_(a,h)};i,x;*f(z g){int j[24]={0};char*c;double w;for(x=0;x++<9;)p!j[i]&isnan(w=((z)y[i])(x))-isnan(g(x))|fabs(w-g(x))>1E-9?j[i]=1:0;p!j[i]?c=y[i+1]:0;return c;}

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


14バイトを削除できました。TIOで詳細を確認できます。オンラインでお試しください!
ジャコモガラベッロ

私から+1、しかし私は別の戦略を使用してサブ200ソリューションを見つけました:)
LambdaBeta

3

JavaScript、76 67 66バイト

きれいではありませんが、私はそれを投稿しないようにいくつかのビールを飲みながらウサギの穴をはるかに下に行きました。Nitのソリューションから独立して派生。

b=>Object.getOwnPropertyNames(M=Math).find(x=>M[x](.8)+M==b(.8)+M)

オンラインで試す


b=>Object.getOwnPropertyNames(M=Math).find(x=>M[x](.8)+M==b(.8)+M)?(比較するためにStringに変換する理由はよくわかりませんが)
-l4m2

なぜ私はそれを考えなかったのか分からない。ありがとう、@ l4m2。
シャギー

@ l4m2 NaNと等しいNaNか比較する必要があるので、それはまたはのいずれかですObject.is
ニール



2

JavaScript、108 70バイト

私は長い間、純粋なJavascriptでゴルフをしようとしていないので、ここには改善すべきものがあると確信しています。

t=>Object.getOwnPropertyNames(m=Math).find(f=>m[f](.9,0)+''==t(.9)+'')

Math非常に簡単で、プロトタイプのすべての関数を任意の値(0.9、他の多くの値がおそらく機能する)に対してチェックし、ブラックボックス関数の結果と比較します。
Google Chromeでテストされ、入力ブラックボックス関数がトリガーの1つではない場合は破損します。

ShaggyとNeilのおかげで、大量のバイトを削減できます。

const answer = t=>Object.getOwnPropertyNames(m=Math).find(f=>m[f](.9,0)+''==t(.9)+'');
const tests = [Math.sin, Math.cos, Math.tan, Math.asin, Math.acos, Math.atan, Math.sinh, Math.cosh, Math.tanh, Math.asinh, Math.acosh, Math.atanh];

tests.forEach(test => console.log(test + ' yields ' + answer(test)));


1
私がいくつかのビールで取り組んでいた解決策と非常によく似ていましたが、理解できませんでした。2つの迅速な節約は私が見つけることができます0.3 -> .3し、割り当てるMathにはm getOwnPropertyNames()
シャギー

1
私はこれをなんとか71バイトにまで減らすことができましたt=>Object.getOwnPropertyNames(m=Math).find(f=>m[f](.9,0)+''==t(.9)+'');。@Shaggyも使用さfindれていることに気付きました。+''私たちは一点のみをチェックする必要が意味を比較する文字列は、ありません。,0私たちはスキップますMath.atan2
ニール

@Neil、,0 必要なようには見えません:tio.run
シャギー

@Shaggy実装依存だと思います。Firefoxでは、によって返される配列内でatan2先行acoshObject.getOwnPropertyNamesます。
ニール

誰かが疑問に思っていた場合、このソリューションは、からの最初の非関数getOwnPropertyNamesがMath.Eであり、すべてのtrig関数がその前に列挙されるため、機能します。
MattH

2

R、75バイト

function(b)Find(function(x)get(x)(1i)==b(1i),apropos('(sin|cos|tan)(h|$)'))

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

今のところ(R v3.5)動作します。
将来のRバージョンで、この正規表現に一致する関数が追加される場合、誰が:Pを知っているか

  • @Giuseppeのおかげで-2バイト
  • @JayCeのおかげで-9バイト
  • -2バイトのFind代わりに使用for

ワオ。非常に素晴らしい!-2バイトで1iも動作すると思い-1iます。
ジュゼッペ

@ジュゼッペ:私はそれをテストしたと確信していました、そして、それは働いていませんでした...しかし、おそらくそれは私の想像だけでした:D
digEmAll

非常に素晴らしい!TIOで動作しますが、おそらく一般的なケースでは設定に依存します:tio
JayCe

@JayCe:位置を介して環境を取得するのは危険です...たとえば、RStudioでは機能しません...残念ながら、同じバイト数でどこでもオブジェクトを検索する別の関数を見つけました:)
digEmAll

最後に... GETは短く(77)
JayCe

1

HP 49G RPL、10バイトのプログラムヘッダーを除く88.0バイト

複素数を使用する別のソリューション!COMPLEX、APPROXモードで入力して実行します。スタック上の関数を受け取ります。

2. SWAP EVAL { SIN COS TAN ASIN ACOS ATAN SINH COSH TANH ASINH ACOSH ATANH }
DUP 1. << 2. SWAP EVAL >> DOLIST ROT - ABS 0. POS GET

(改行は関係ありません)

定数2.0の場合、12個のトリガー関数すべてが複素平面で定義されているため、12個すべてを評価し、どれが一致するかを確認します。今回は、それを取得するために必要なスタックシャッフルのため、反復ソリューションはより長くなります(111.5バイト)。RPLは、私が知る限り、ループから抜け出すことを早めにさせません。


大文字で返される場合は、チャレンジを編集したので問題ありません。
ライコニ

@JungHwanMinこれらは大文字です。キャッチしてくれてありがとう!->STR DUP SIZE 3 - " " " " IFTE XOR、34.5バイトで小文字に変更できます。(それぞれ4スペースと3スペースが想定されています)
ジェイソン

1

Perl 6、39バイト

{i.^methods.first({try $^a.(i)==.(i)})}

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

物事の見た目で、内省を使用する数少ないの一つ。iここに複素数があり、その値は各トリガー関数に対して一意であるため、すべてのメソッドを反復処理することで、一致するメソッドを見つけ、その名前を暗黙的に吐き出すことができます。tryいくつかの(不要な)方法は、異なるシグネチャを持つように必要とされます。


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