C (gcc) , 178 172 байт
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?-_:_]);}
Спробуйте в Інтернеті!
Старий, але крутий: C (gcc) , 194 байт
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}[_]);}
Спробуйте в Інтернеті!
-lm
Перемикач в TIO просто перевірити. Якби ви могли написати ідеальну
реалізацію стандартних триггерних функцій, ви отримаєте правильну відповідь.
Пояснення
Ідея полягала в тому, щоб знайти якесь вхідне значення таким, що коли я інтерпретую виходи кожної з функцій триггеру як цілі числа, вони мають різні залишки модуля 12. Це дозволить використовувати їх як індекси масиву.
Для того щоб знайти таке вхідне значення, я написав такий фрагмент:
#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;
}
Якщо запустити це (що потрібно скомпілювати з -lm), виплюне, що зі значенням 0,9247 ви отримаєте унікальні значення.
Далі я повторно ввів цілі числа, застосував модуль на 12 і прийняв абсолютне значення. Це давало кожній функції індекс. Вони були (від 0 -> 11): акош, син, асінь, атан, загар, кош, асин, гріх, сос, атан, тань, аксос.
Тепер я міг просто індексувати масив рядків, але назви дуже довгі та дуже схожі, тому замість цього я виймаю їх із фрагментів рядка.
Для цього я будую рядок "asinhacoshatanh" і два масиви. Перший масив вказує, який символ у рядку потрібно встановити на нульовий термінатор, а другий вказує, який символ у рядку повинен бути першим. Ці масиви містять: 10,5,5,0,14,10,4,4,9,14,0,9 та 5,1,0,10,11,6,0,1,6,10,11, 5 відповідно.
Нарешті, це було лише питанням ефективного впровадження алгоритму реінтерпретації в C. На жаль, мені довелося використовувати подвійний тип, і з точно трьома способами використання було швидше просто double
три рази просто використовувати #define D double\nDDD
лише два символи. Результат вище, опис нижче:
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
Редагувати: На жаль, просто використання необробленого масиву насправді коротше, тому код стає набагато простішим. Тим не менш нарізка струн була веселою. Теоретично відповідний аргумент насправді може скласти правильні фрагменти самостійно з деякою математикою.