C (gcc) , 178 172 bytes
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?-_:_]);}
Experimente online!
Antigo, mas interessante: C (gcc) , 194 bytes
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}[_]);}
Experimente online!
A -lm
opção no TIO é apenas para testar. Se você pudesse escrever uma
implementação perfeita das funções trigonométricas padrão, obteria a resposta certa.
Explicação
A idéia era encontrar algum valor de entrada tal que, quando eu interpreto as saídas de cada uma das funções trigonométricas como números inteiros, elas tenham diferentes remanescentes no módulo 12. Isso permitirá que elas sejam usadas como índices de matriz.
Para encontrar esse valor de entrada, escrevi o seguinte trecho:
#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;
}
Se você executar isso (que precisa ser compilado com -lm), ele citará que, com um valor de 0,9247, você obtém valores exclusivos.
Em seguida, reinterpetuei como números inteiros, apliquei o módulo em 12 e peguei o valor absoluto. Isso deu a cada função um índice. Eles eram (de 0 a 11): acosh, sinh, asinh, atanh, tan, cosh, asin, pecado, cos, atan, tanh, acos.
Agora eu poderia apenas indexar em uma matriz de seqüências de caracteres, mas os nomes são muito longos e muito semelhantes; portanto, eu os retiro das fatias de uma sequência.
Para fazer isso, construo a string "asinhacoshatanh" e duas matrizes. A primeira matriz indica qual caractere da string deve ser definido como terminador nulo, enquanto a segunda indica qual caractere da string deve ser o primeiro. Essas matrizes contêm: 10,5,5,0,14,10,4,4,9,14,0,9 e 5,1,0,10,11,6,0,1,6,10,11, 5 respectivamente.
Finalmente, era apenas uma questão de implementar o algoritmo de reinterpretação de forma eficiente em C. Infelizmente, eu tive que usar o tipo duplo e, com exatamente 3 usos, foi mais rápido usar apenas double
três vezes e usar #define D double\nDDD
apenas 2 caracteres. O resultado está acima, uma descrição está abaixo:
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
Edit: Infelizmente, apenas o uso de uma matriz bruta é realmente mais curto, portanto o código se torna muito mais simples. No entanto, o corte das cordas foi divertido. Em teoria, um argumento apropriado pode, na verdade, apresentar as fatias certas por conta própria com um pouco de matemática.