C (gcc) , 178 172 byte
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?-_:_]);}
Provalo online!
Vecchio ma interessante: C (gcc) , 194 byte
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}[_]);}
Provalo online!
Lo -lm
switch in TIO è semplicemente da testare. Se potessi scrivere a
un'implementazione perfetta delle funzioni trig standard, otterrai la risposta giusta.
Spiegazione
L'idea era quella di trovare un valore di input in modo tale che quando interpreto le uscite di ciascuna delle funzioni di trigma come numeri interi abbiano dei rimanenti moduli 12. Ciò consentirà loro di essere usati come indici di array.
Per trovare tale valore di input ho scritto il seguente frammento:
#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 lo esegui (che deve essere compilato con -lm) si sputerà che con un valore di 0.9247 otterrai valori univoci.
Successivamente ho reinterpretato come numeri interi, ho applicato il modulo per 12 e ho preso il valore assoluto. Ciò ha dato a ciascuna funzione un indice. Erano (da 0 a> 11): acosh, sinh, asinh, atanh, tan, cosh, asin, sin, cos, atan, tanh, acos.
Ora potrei semplicemente indicizzare in una matrice di stringhe, ma i nomi sono molto lunghi e molto simili, quindi invece li tolgo da sezioni di una stringa.
Per fare questo costruisco la stringa "asinhacoshatanh" e due array. Il primo array indica quale carattere nella stringa deve essere impostato sul terminatore null, mentre il secondo indica quale carattere nella stringa dovrebbe essere il primo. Questi array contengono: 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 rispettivamente.
Alla fine, si trattava solo di implementare l'algoritmo di reinterpretazione in modo efficiente in C. Purtroppo, ho dovuto usare il doppio tipo e, con esattamente 3 usi, è stato più veloce usarlo double
tre volte e poi usarlo #define D double\nDDD
con solo 2 caratteri. Il risultato è sopra, una descrizione è sotto:
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
Modifica: Sfortunatamente il solo utilizzo di un array raw è in realtà più breve, quindi il codice diventa molto più semplice. Ciò nonostante, il taglio delle corde è stato divertente. In teoria un argomento appropriato potrebbe in realtà trovare le giuste sezioni da solo con un po 'di matematica.