C (gcc) , 178 172 bayt
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?-_:_]);}
Çevrimiçi deneyin!
Eski ama havalı: C (gcc) , 194 bayt
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}[_]);}
Çevrimiçi deneyin!
-lm
TIO anahtar testine oluşurdu.
Standart trig fonksiyonlarının mükemmel bir uygulamasını yazabilirseniz doğru cevabı alırsınız.
açıklama
Buradaki düşünce, trig fonksiyonlarının her birinin çıktılarını tamsayılar olarak yorumladığımda, farklı modüller 12'ye sahip olacakları için bazı girdi değerleri bulmaktı.
Böyle bir giriş değeri bulmak için aşağıdaki pasajı yazdım:
#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;
}
Eğer (-lm ile derlenmesi gereken) çalıştırırsanız, 0.9247 değerinde benzersiz değerler elde edersiniz.
Daha sonra tamsayı olarak yeniden yorumladım, 12'ye kadar modulo uyguladım ve mutlak değeri aldım. Bu her fonksiyona bir indeks verdi. Onlar (0 -> 11 arasında): acosh, sinh, asin, atanh, tan, cosh, asin, günah, cos, atan, tanh, acos.
Şimdi sadece bir dizge dizini indeksleyebildim, ancak isimler çok uzun ve çok benzer, bunun yerine onları bir dize dilimlerinden alıyorum.
Bunu yapmak için "asinhacoshatanh" dizesini ve iki diziyi yapıyorum. İlk dizi, dizgede hangi karakterin boş sonlandırıcıya ayarlanacağını belirtirken, ikincisi dizideki hangi karakterin ilk karakter olacağını belirtir. Bu diziler şunları içerir: 10,5,5,0,14,10,4,4,9,14,0,9 ve 5,1,0,10,11,6,0,1,6,10,11, Sırasıyla 5.
Son olarak, yeniden yorumlama algoritmasını C'de verimli bir şekilde uygulama meselesiydi. Ne yazık ki çift tipi kullanmak zorunda kaldım ve tam olarak 3 kullanımla,
sadece 2 karakter double
kullanmak için sadece üç kez kullanmak daha hızlıydı #define D double\nDDD
. Sonuç yukarıda, bir açıklama aşağıdadır:
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
Düzenleme: Ne yazık ki sadece ham bir dizi kullanarak aslında daha kısa, bu yüzden kod çok daha basit hale gelir. Bununla birlikte, dize dilimleme eğlenceliydi. Teoride, uygun bir argüman aslında bazı matematiklerle birlikte kendi başına doğru dilimlerle ortaya çıkabilir.