黑匣子三角法


29

写一个程序或功能,可以区分以下12个三角函数: sincostanasinacosatansinhcoshtanhasinhacoshatanh

您的程序将上面的功能之一称为黑匣子,并且应按照上面给出的名称或以您的语言命名的方式输出该函数的名称。

这是,因此每种语言中最短的答案将获胜。您应该通过包含所有12种可能的输入的测试用例来证明您的代码可以正常工作。如果您选择的语言不包含上述所有功能的内建函数,则您必须为缺失的函数提供自己的明智实现。

进一步说明

  • 如果基础内建程序可以处理复数,则允许使用复数查询黑盒。
  • 由于仅使用实数时,对黑盒函数的查询可能会给出域错误。在这种情况下,您应该假设黑匣子仅传达错误的存在,而不传达错误的来源。dØ 一种CØsHdØ 一种Ť一种ñH=
  • 如果返回的不是其他错误(例如NaNnull),则您的提交应该能够处理它们。

感谢您提供有用的沙盒反馈


1
Mathematica可以处理符号输入,以便仅对函数输出进行部分评估(如果有的话)。它的区别在于,我可以使用某些模式匹配而不是计算。
JungHwan Min

1
@JungHwanMin如果这意味着您可以从符号输出中访问函数名称,那么恐怕是不允许的。
Laikoni '18

Answers:


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我相信你很困惑。我当然可以承担实际职能。请注意,我对输入的唯一参考ff(.029)-用值调用函数。
orlp

1
你强暴了吗?
mbomb007 '18

4
@ mbomb007如果使用蛮力,您的意思是一个循环,眨眼之间就完成了数百次迭代,是的。
orlp

3
这既惊人又愚蠢。
Nit


6

Perl 6,75个字节

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

在线尝试!

碰巧的是,要区别的所有十二个函数都是内置的,并且都带有复杂的参数。

[X~] ("", "a"), <sin cos tan>, ("", "h")通过使用叉积串联减少三个输入列表来生成所有十二个函数名称。给定那些,在处.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中的切换仅用于测试。如果您可以编写 标准触发函数的完美实现,则将获得正确的答案。

说明

想法是找到一些输入值,以便当我将每个trig函数的输出解释为整数时,它们的模数为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中高效实现重新解释算法的问题。可悲的是,我不得不使用double类型,并且恰好有3种用法,使用double3次比使用#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并用替换所有doubles,从而节省5个字节D。注意,该标志需要计算总字节数。

可以通过替换char*[]int*[],以及通过将三元运算符(?:)更改为abs(_)

6

Python的3.6.5在Linux上,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”放置字符串文字来节省字节,而不是一次构建一个答案。

第一个幻数用于确定它是“弧”三角函数中的一个,相应地在其前面加上“ a”,第二个幻数用于确定它是基于“ sin”,“ cos”或“ tan”的函数中的一个,选择相应的字符串,以及第三个字符串(是否为双曲函数之一),相应地附加一个“ 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 '18

谢谢!我只是添加了代码来找到答案的魔幻数字,尽管它并不十分漂亮。
nthistle

4

Python108 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]

在线尝试

乔纳森·艾伦的 -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 '18

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中,您可以找到详细信息。在线尝试!
Giacomo Garabello '18

向我+1,但我确实找到了使用另一种策略的sub 200解决方案:)
LambdaBeta

3

JavaScript,76 67 66字节

不是很漂亮,但是我在兔子洞里走得太远了,用了几瓶啤酒就不张贴了。独立于Nit解决方案而派生。

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

在线尝试

  • 感谢尼尔节省了6个字节
  • l4m2节省了1个再见

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中进行了测试,它将中断。

多亏了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,看起来好像,0 不是必需的:tio.run/##Lc6xDoMgEMbxvU/RMEFq2TvgG1jdjYknomLkzghp7dPTqEz/…
毛茸茸的

@Shaggy我想这取决于实现;在Firefox中,atan2位于之前acosh由返回的数组中Object.getOwnPropertyNames
尼尔,

如果有人想知道,该解决方案之所以有效,getOwnPropertyNames是因为Math.E中的第一个非函数是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

  • -2个字节,感谢@Giuseppe
  • -9个字节,感谢@JayCe
  • -2个字节使用Find代替for

哇。非常好!我觉得1i作品以及-1i为-2个字节。
朱塞佩

@Giuseppe:我确定我已经测试过了它,但是它没有用...但是可能只是我的想象力:D
digEmAll

非常好!在TIO上工作,一般情况下取决于您的配置:tio
JayCe

@JayCe:通过位置获取环境是有风险的...例如,它在RStudio中不起作用...很幸运,我发现了另一个函数,该函数在各处搜索具有相同字节数的对象:)
digEmAll


1

HP 49G RPL,88.0字节,不包括10字节程序头

使用复数的另一种解决方案!输入并以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,在复杂平面中定义了所有十二个trig函数,因此我们只求这十二个函数的总和,看看哪一个匹配。这次,迭代解决方案更长(111.5字节),因为获得它所需的堆栈改组。据我所知,RPL不允许您提早退出循环。


如果它们以大写形式返回,那么在我编辑挑战时就可以了。
Laikoni '18

@JungHwanMin它们是大写的。感谢您的接见!可以将其修改为->STR DUP SIZE 3 - " " " " IFTE XOR34.5字节的小写字母。(应该分别是4和3个空格)
Jason

1

Perl 6,39个字节

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

在线尝试!

从事物的外观来看,这是使用自省的少数几个。i这是复数,每个触发器函数的值都是唯一的,因此,通过迭代所有方法,我们可以找到匹配的方法并隐式吐出其名称。将try需要一些(不想要的)方法有不同的签名。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.