블랙 박스 삼각법


29

다음 (12 개) 삼각 함수를 구별 할 수있는 프로그램 또는 기능을 쓰기 : sin, cos, tan, asin, acos, atan, sinh, cosh, tanh, asinh, acosh, atanh.

귀하의 프로그램은 위의 기능 중 하나를 블랙 박스 로 제공받으며 위와 같이 또는 해당 언어로 명명 된 방식으로 기능의 이름을 출력해야합니다.

이것은 이므로 각 언어에서 가장 짧은 답변이 이깁니다. 12 개의 가능한 입력이 모두있는 테스트 사례를 포함하여 코드가 올바르게 작동 함을 보여 주어야합니다. 선택한 언어에 위의 모든 기능에 대한 내장 기능이 포함되어 있지 않은 경우 누락 된 기능에 대해 현명한 구현을 제공해야합니다.

추가 설명

  • 기본 빌드-인이이를 처리 할 수있는 경우 복잡한 숫자를 사용하여 블랙 박스를 쿼리하는 것이 허용됩니다.
  • 로 유일한 번호를 사용하는 경우, 블랙 박스 기능에 대한 쿼리를 줄 수있는 도메인 오류. 이 경우 블랙 박스는 오류의 존재만을 전달하지만 어떤 기능에서 발생하지는 않았다고 가정해야합니다.dom acoshdom atanh=
  • 오류 대신 다른 값 (예 : NaN또는 null)이 반환되면 제출 한 값 을 처리 할 수 ​​있어야합니다.

유용한 샌드 박스 피드백에 감사드립니다 !


1
Mathematica는 함수 입력이 부분적으로 만 평가되도록 기호 입력을 처리 할 수 ​​있습니다. 차이점은 계산 대신 패턴 일치를 사용할 수 있다는 것입니다.
JungHwan Min

1
@JungHwanMin 만약 당신이 심볼릭 출력에서 ​​함수 이름에 접근 할 수 있다면 그것이 허용되지 않을까 걱정됩니다.
Laikoni

답변:


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복잡한 입 / 출력을 위해 삼각 함수가 내장 모듈 중 하나 여야 합니다.


2
@JungHwanMin 나는 당신이 혼란스러워 생각합니다. 나는 확실히 실제 기능을 수행합니다. 참고 입력 내 유일한 기준은 f있다 f(.029)- 값이 함수를 호출.
orlp

1
이거 무차별 했습니까?
mbomb007

4
@ mbomb007 무차별 적으로 눈이 깜박일 때 수백 번 반복되는 루프를 의미한다면, 그렇습니다.
orlp

3
이것은 놀랍고 바보입니다.
Nit


6

펄 6 , 75 바이트

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

온라인으로 사용해보십시오!

이와 같이, 구별되는 12 가지 기능은 모두 내장되어 있으며 모두 복잡한 주장을 취합니다.

[X~] ("", "a"), <sin cos tan>, ("", "h")교차 제품 연결로 세 개의 입력 목록을 줄여 12 개의 함수 이름을 모두 생성합니다. 주어진 점 .min(...)에서의 입력 함수와 가장 작은 점을 찾습니다 2i.


59 바이트 X 는 여러 용어로 사용할 수 있으며 골프 바이트에 대한 몇 가지 다른 트릭
Jo King

6

C (gcc) , 178172 바이트

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"와 두 개의 배열을 구성합니다. 첫 번째 배열은 문자열에서 널 종료 자로 설정할 문자를 나타내고 두 번째 배열은 문자열에서 어떤 문자가 첫 번째 문자 여야하는지 나타냅니다. 이 배열에는 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에서 재 해석 알고리즘을 효율적으로 구현하는 문제였습니다. 슬프게도 이중 유형을 사용해야했고 정확히 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

편집 : 불행히도 원시 배열을 사용하는 것이 실제로 더 짧으므로 코드가 훨씬 간단 해집니다. 그럼에도 불구하고 줄 슬라이싱은 재미있었습니다. 이론적으로 적절한 논증은 실제로 약간의 수학으로 올바른 조각을 내놓을 수 있습니다.


puts(...)printf("%.5s","acoshsinh asinhatanhtan cosh asin sin cos atan tanh acos "+5*(_<0?-_:_))
Curtis Bechtel

코드의 -DD=double모든 을 컴파일 하고로 바꾸면 5 바이트를 절약 할 수 있습니다 . 플래그는 총 바이트 수로 계산되어야합니다. doubleD

추가의 3 바이트가 교체하여 흘릴 수 char*[]int*[], 그리고 (원계 연산자를 변경함으로써 :) 내지 An?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"에 대한 문자열 리터럴을 여러 번 넣지 않고 한 번에 하나씩 파트를 작성하여 바이트를 절약합니다.

첫 번째 매직 넘버는 "arc"삼각 함수 중 하나인지, 그에 따라 "a"를 붙이고, 두 번째는 "sin", "cos"또는 "tan"기반 함수 중 하나인지를 결정하는 데 사용됩니다. 적절한 문자열, 그리고 세 번째는 쌍곡선 함수 중 하나인지 여부에 따라 "h"를 추가합니다.

orlp의 답변과 마찬가지로 Python의 내장 cmath모듈 의 함수를 입력으로 사용합니다.

슬라이스 인덱싱을 사용하여 중간 문자열로 5 바이트 절약

매직 넘버 찾기

완벽을 기하기 위해 여기에 마법의 숫자를 찾는 데 사용한 스크립트가 있습니다. 나는 주로 파이썬 터미널에서 바로 일 했으므로 코드가 지저분하지만 작업이 완료됩니다.

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

파이썬 , 108 94 90 바이트

입력 함수의 결과를 값에 대한 모든 함수의 결과와 비교합니다 .2.

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

온라인으로 사용해보십시오

Jonathan Allen -14 바이트 Rod
-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=계산되지에 헤더에 있어야합니다)를.
Jonathan Allan


아주 좋아요! 감사합니다
mbomb007

4

Dyalog APL , 25 21 19 바이트

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

온라인으로 사용해보십시오!

H.PWiz 덕분에 -3 ngn
덕분에 -2

필요한 모든 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)-lm, 374 (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에서 세부 사항을 찾을 수 있습니다. 온라인으로 사용해보십시오!
Giacomo Garabello

+1,하지만 다른 전략을 사용하여 하위 200 솔루션을 찾았습니다 :)
LambdaBeta

3

자바 스크립트, 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)? (왜 문자열로 변환하여 비교
해야하는지 잘 모르겠지만

내가 왜 그런 생각을하지 않았는지 모르겠다. 감사합니다, @ l4m2.
얽히고 설킨

@ l4m2와 NaN같음을 비교 해야 NaN하므로, 또는 Object.is입니다.
Neil



2

자바 스크립트, 108 70 바이트

나는 순수한 자바 스크립트로 골프를 시도하지 않았으므로 여기에서 개선해야 할 것이 확실합니다.

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

매우 간단하며 Math프로토 타입의 모든 함수를 임의의 값 (0.9, 다른 많은 값이 작동 할 수 있음)과 비교하여 블랙 박스 함수의 결과와 비교합니다.
입력 된 블랙 박스 기능이 삼각법 중 하나가 아닌 경우 Chrome에서 테스트되었습니다.

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및 지정 Mathm getOwnPropertyNames() .
얽히고 설킨

1
나는 이것을 71 바이트로 줄였다 t=>Object.getOwnPropertyNames(m=Math).find(f=>m[f](.9,0)+''==t(.9)+'');. @Shaggy도 사용 find되었습니다. 는 +''문자열 우리는 하나의 점을 확인해야 의미 비교한다. 은 ,0우리를 건너 뛸 수 있습니다 Math.atan2.
Neil

@Neil, 그것은 필요하지 않은 것 같습니다 ,0 : tio.run/##Lc6xDoMgEMbxvU/RMEFq2TvgG1jdjYknomLkzghp7dPTqEz/…
Shaggy

@Shaggy 구현에 따라 다릅니다. Firefox에서는으로 반환 된 배열이 atan2앞에옵니다 . acoshObject.getOwnPropertyNames
Neil

궁금한 점이 있다면이 솔루션은 작동하지 않는 첫 번째 함수 getOwnPropertyNames가 Math.E이므로 모든 삼각 함수가 그 전에 열거되기 때문입니다.
MattH

2

R , 75 바이트

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

온라인으로 사용해보십시오!

현재 (R v3.5) 작동합니다.
향후 R 버전 에서이 정규식과 일치하는 함수가 추가되면 누가 알 수 있습니까?

  • @Giuseppe 덕분에 -2 바이트
  • @JayCe 덕분에 -9 바이트
  • Find대신에 -2 바이트 사용for

와우. 아주 좋아요! -2 바이트 1i뿐만 아니라 작동 한다고 생각 합니다 -1i.
주세페

@ 주세페 : 나는 그것을 테스트했고 그것이 작동하지 않았다고 확신했지만 ... 아마 그것은 나의 상상 일 뿐이다 : D
digEmAll

아주 좋은! TIO에서 작동하며, 일반적인 경우 구성에 따라 다릅니다. tio
JayCe

@JayCe : 위치를 통해 환경을 얻는 것은 위험합니다 ... 예를 들어 RStudio에서 작동하지 않습니다 ... 다행히도 동일한
바이트 수로

마지막으로 ... 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은 내가 아는 한 일찍 루프에서 벗어날 수 없습니다.


대문자로 반환 된 경우 도전 과제를 편집해도 괜찮습니다.
Laikoni

@JungHwanMin 대문자입니다. 캐치 주셔서 감사합니다! ->STR DUP SIZE 3 - " " " " IFTE XOR34.5 바이트 로 소문자로 수정할 수 있습니다 . (각각 4 칸과 3 칸으로되어 있습니다)
Jason

1

펄 6 , 39 바이트

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

온라인으로 사용해보십시오!

사물을 살펴보면 몇 가지 중 하나를 사용하여 내성을 검사합니다. i여기에는 각 삼각 함수에 고유 한 값을 갖는 복소수가 있으므로 모든 방법을 반복하여 일치하는 방법을 찾고 암시 적으로 이름을 뱉어 낼 수 있습니다. 은 try일부 (원치 않는) 방법은 다른 서명을 가지고 필요합니다.


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.