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?-_:_]);}
Probieren Sie es online!
Alt aber cool: 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}[_]);}
Probieren Sie es online!
Der -lm
Schalter in TIO dient lediglich zum Testen. Wenn Sie eine perfekte
Implementierung der Standard-Triggerfunktionen schreiben könnten, würden Sie die richtige Antwort erhalten.
Erläuterung
Die Idee war, einen Eingabewert so zu finden, dass, wenn ich die Ausgaben jeder der Triggerfunktionen als Ganzzahlen interpretiere, sie unterschiedliche Reste modulo 12 haben. Dadurch können sie als Array-Indizes verwendet werden.
Um einen solchen Eingabewert zu finden, habe ich folgendes Snippet geschrieben:
#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;
}
Wenn Sie das ausführen (was mit -lm kompiliert werden muss), wird darauf hingewiesen, dass Sie mit einem Wert von 0,9247 eindeutige Werte erhalten.
Als nächstes habe ich als ganze Zahlen neu interpretiert, modulo mit 12 angewendet und den absoluten Wert genommen. Dies gab jeder Funktion einen Index. Sie waren (von 0 -> 11): acosh, sinh, asinh, atanh, tan, cosh, asin, sin, cos, atan, tanh, acos.
Jetzt konnte ich nur eine Reihe von Zeichenfolgen indizieren, aber die Namen sind sehr lang und sehr ähnlich, und stattdessen nehme ich sie aus Schnitten einer Zeichenfolge heraus.
Dazu konstruiere ich den String "asinhacoshatanh" und zwei Arrays. Das erste Array gibt an, welches Zeichen in der Zeichenfolge als Nullterminator festgelegt werden soll, während das zweite angibt, welches Zeichen in der Zeichenfolge das erste sein soll. Diese Arrays enthalten: 10,5,5,0,14,10,4,4,9,14,0,9 und 5,1,0,10,11,6,0,1,6,10,11, 5 jeweils.
Schließlich ging es nur darum, den Neuinterpretationsalgorithmus in C effizient zu implementieren. Leider musste ich den Doppeltyp verwenden, und mit genau drei Verwendungen war es schneller, nur double
drei Mal zu verwenden, als #define D double\nDDD
mit nur zwei Zeichen. Das Ergebnis ist oben, eine Beschreibung ist unten:
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
Bearbeiten: Leider ist nur die Verwendung eines unformatierten Arrays tatsächlich kürzer, sodass der Code viel einfacher wird. Trotzdem hat das Aufschneiden der Saiten Spaß gemacht. Theoretisch könnte ein geeignetes Argument mit etwas Mathematik tatsächlich die richtigen Schichten für sich finden.