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?-_:_]);}
Cobalah online!
Tua tapi keren: 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}[_]);}
Cobalah online!
The -lm
switch TIO adalah hanya untuk tes. Jika Anda bisa menulis
implementasi sempurna fungsi trigonometri standar, Anda akan mendapatkan jawaban yang tepat.
Penjelasan
Idenya adalah untuk menemukan beberapa nilai input sehingga ketika saya menginterpretasikan output dari masing-masing fungsi trig sebagai bilangan bulat mereka memiliki modulo sisa yang berbeda 12. Ini akan memungkinkan mereka untuk digunakan sebagai indeks array.
Untuk menemukan nilai input seperti itu, saya menulis cuplikan berikut:
#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;
}
Jika Anda menjalankan itu (yang perlu dikompilasi dengan -lm) itu akan memuntahkan bahwa dengan nilai 0,9247 Anda mendapatkan nilai-nilai unik.
Selanjutnya saya reinterpeted sebagai integer, menerapkan modulo oleh 12, dan mengambil nilai absolut. Ini memberi masing-masing fungsi indeks. Mereka (dari 0 -> 11): acosh, sinh, asinh, atanh, tan, cosh, asin, dosa, cos, atan, tanh, acos.
Sekarang saya hanya bisa mengindeks ke array string, tetapi nama-nama yang sangat panjang dan sangat mirip, jadi alih-alih saya mengambilnya dari potongan string.
Untuk melakukan ini saya membangun string "asinhacoshatanh" dan dua array. Array pertama menunjukkan karakter mana dalam string yang akan ditetapkan ke terminator nol, sedangkan yang kedua menunjukkan karakter mana dalam string harus yang pertama. Array ini berisi: 10,5,5,0,14,10,4,4,9,9,14,0,9 dan 5,1,0,10,11,6,0,1,1,6,10,11, 5 masing-masing.
Akhirnya itu hanya masalah menerapkan algoritma reinterpretasi secara efisien dalam C. Sayangnya saya harus menggunakan tipe ganda, dan dengan tepat 3 penggunaan, lebih cepat hanya menggunakan double
tiga kali kemudian menggunakan #define D double\nDDD
hanya 2 karakter. Hasilnya di atas, uraiannya di bawah:
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
Sunting: Sayangnya hanya menggunakan array mentah sebenarnya lebih pendek, sehingga kode menjadi lebih sederhana. Meskipun demikian, mengiris senar itu menyenangkan. Secara teori, argumen yang tepat mungkin benar-benar muncul dengan irisan yang tepat dengan beberapa matematika.