C (gcc) , 178 172 octets
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?-_:_]);}
Essayez-le en ligne!
Vieux mais cool: C (gcc) , 194 octets
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}[_]);}
Essayez-le en ligne!
Le -lm
commutateur dans TIO est simplement à tester. Si vous pouviez écrire une
implémentation parfaite des fonctions trigonométriques standard, vous obtiendriez la bonne réponse.
Explication
L'idée était de trouver une valeur d'entrée telle que lorsque j'interprète les sorties de chacune des fonctions trigonométriques comme des nombres entiers, elles aient différents restes modulo 12. Cela leur permettra d'être utilisées comme indices de tableau.
Afin de trouver une telle valeur d'entrée, j'ai écrit l'extrait suivant:
#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;
}
Si vous exécutez cela (qui doit être compilé avec -lm), il crachera qu'avec une valeur de 0,9247, vous obtenez des valeurs uniques.
Ensuite, j'ai réinterprété comme des nombres entiers, appliqué le module par 12 et pris la valeur absolue. Cela a donné à chaque fonction un indice. Ils étaient (de 0 à> 11): acosh, sinh, asinh, atanh, tan, cosh, asin, sin, cos, atan, tanh, acos.
Maintenant, je pourrais simplement indexer dans un tableau de chaînes, mais les noms sont très longs et très similaires, donc je les retire à la place des tranches d'une chaîne.
Pour ce faire, je construis la chaîne "asinhacoshatanh" et deux tableaux. Le premier tableau indique le caractère de la chaîne à définir sur le terminateur nul, tandis que le second indique quel caractère de la chaîne doit être le premier. Ces tableaux contiennent: 10,5,5,0,14,10,4,4,9,14,0,9 et 5,1,0,10,11,6,0,1,6,10,11, 5 respectivement.
Enfin, il s'agissait simplement d'implémenter efficacement l'algorithme de réinterprétation en C. Malheureusement, je devais utiliser le double type, et avec exactement 3 utilisations, il était plus rapide de n'utiliser que double
trois fois puis d'utiliser #define D double\nDDD
seulement 2 caractères. Le résultat est au-dessus, une description est ci-dessous:
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: Malheureusement, l'utilisation d'un tableau brut est en fait plus courte, donc le code devient beaucoup plus simple. Néanmoins, le tranchage des cordes était amusant. En théorie, un argument approprié pourrait en fait produire les bonnes tranches avec des mathématiques.