Kara Kutu Trigonometrisi


29

Aşağıdaki 12 trigonometrik fonksiyonlar ayırabilecek program veya fonksiyon yazın: sin, cos, tan, asin, acos, atan, sinh, cosh, tanh, asinh, acosh, atanh.

Programınıza yukarıdaki fonksiyonlardan biri kara kutu olarak verilmiştir ve işlevin adını yukarıda belirtildiği gibi ya da kendi dilinizde adlandırılmış şekilde vermelidir.

Bu , yani her dilde en kısa cevap kazanır. Mümkün olan 12 girişin tümü ile test durumları ekleyerek kodunuzun doğru çalıştığını göstermelisiniz. Seçtiğiniz dil, yukarıdaki işlevlerin tümü için yerleşik bileşenler içermiyorsa, eksik olanların kendi mantıklı uygulamalarınızı sağlamanız gerekir.

Diğer Açıklamalar

  • Kara kutu sorgulamak için karmaşık sayılar kullanmaya, altta yatan derlemeler bunları kaldırabilirse izin verilir.
  • Şöyle tek gerçek sayılar kullanıldığında, kara kutu işlevi sorgular alan hataları verir. Bu durumda, kara kutunun yalnızca bir hatanın varlığını ilettiğini, ancak hangi işlevden kaynaklandığını ilettiğini varsaymalısınız.dom acoshdom atanh=
  • Bir hata yerine, başka bir değer, örneğin, NaNveya null, döndürülürse, gönderiminiz bunları idare edebilmelidir.

Yardımcı sanal alan geribildirimi için teşekkür ederiz !


1
Mathematica, sembolik girişleri kaldırabilir, böylece işlev çıktısı yalnızca kısmen değerlendirilir. Yaptığı fark hesaplamalar yerine bazı kalıp-eşleştirmeleri kullanabilmemdir.
JungHwan Min,

1
@JungHwanMin Bu, fonksiyon adlarına sembolik çıktıdan erişebileceğiniz anlamına gelirse, korkarım ki izin verilmiyor.
Laikoni

Yanıtlar:


22

Linux'ta Python 3.6.4, 99 bayt

Aptal bir cevap biraz, ama:

lambda f:"asinh acos cos cosh atan atanh tan sin asin tanh sinh acosh".split()[hash(f(.029))%19%12]

Trigonometrik fonksiyonların cmathkarmaşık giriş / çıkış için yerleşik modülden biri olmasını gerektirir .


2
@JungHwanMin Kafanız karıştığına inanıyorum. Kesinlikle gerçek bir işlev görüyorum. Not girişine benim tek referans olduğunu fedilir f(.029)- bir değerle işlevini çağırarak.
orlp

1
Bunun için kaba davrandın mı?
mbomb007

4
@ mbomb007 Eğer kaba kuvvet ile bir göz açıp kapayıncaya kadar birkaç yüz yineleme yapan bir döngü kastediyorsanız, evet.
orlp

3
Bu hem şaşırtıcı hem de saçma.
Nit


6

Perl 6 , 75 bayt

->&f {([X~] ("","a"),<sin cos tan>,("","h")).min({abs(f(2i)-&::($_)(2i))})}

Çevrimiçi deneyin!

Olduğu gibi, birbirinden ayrılacak olan fonksiyonların oniki tanesi yerleşiktir ve hepsi karmaşık argümanlara sahiptir.

[X~] ("", "a"), <sin cos tan>, ("", "h")ürünler arası birleştirme ile üç giriş listesini azaltarak tüm on iki işlev adını oluşturur. Bunlar göz önüne alındığında .min(...), giriş işlevindeki en küçük fark olanı bulur 2i.


59 bayt X birden fazla terim için kullanılabilir ve golf baytlarında birkaç püf noktası daha var
Jo King

6

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!

-lmTIO 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 doublekullanmak 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.


Sen değiştirerek 20 bayt kaydedebilirsiniz puts(...)ileprintf("%.5s","acoshsinh asinhatanhtan cosh asin sin cos atan tanh acos "+5*(_<0?-_:_))
Curtis Bechtel

Kodunuzdaki -DD=doubletüm s'leri derleyerek ve değiştirerek 5 byte tasarruf edebilirsiniz . Bayrağın toplam bayt için sayılması gerektiğine dikkat edin. doubleD

Ek bir üç bayt değiştirerek döken edilebilir char*[]ile int*[]ve (üçlü operatör değiştirerek :) bir nasıl?abs(_)

6

Linux'ta Python 3.6.5, 90 85 bayt

h=hash;lambda f:h(f(.0869))%3%2*"a"+"tscaionns"[h(f(.14864))%3::3]+h(f(.511))%5%2*"h"

Bu orlp'in cevabı üzerine kuruludur ; ama 1 tane sihirli sayı bulmak yerine, 3 tane buluruz! Bu, temel olarak sadece "sin", "cos" ve "tan" dizgisi dizgisini birden fazla kez kullanmaktan kaçınmak yerine baytları kurtarır, bunun yerine yanıtı her defasında bir kısım oluşturur.

İlk sihir numarası, "ark" trigonometrik fonksiyonlardan biri olup olmadığını belirlemek için kullanılır, buna göre bir "a" hazırlanır, ikincisi "günah", "cos" veya "tan" esaslı fonksiyonlardan biri olup olmadığını seçerek uygun dize ve bunun için "h" ekleyerek, hiperbolik fonksiyonlardan biri olup olmadığı için üçüncü.

Orlp'nin cevabı gibi Python'un yerleşik cmathmodülündeki fonksiyonları giriş olarak kullanır.

Orta dizeye dilim indeksleme kullanılarak 5 bayt kaydedildi

Sihirli Sayıları Bulmak

Bütünlüğü için, işte (az ya da çok) bu sihirli sayıları bulmak için kullandığım komut dosyası. Çoğunlukla doğrudan bir python terminalinde çalıştım, bu yüzden kod dağınıktı, ancak işi alıyor.

import cmath
fns = [(fn, getattr(cmath, fn)) for fn in ["sin","cos","tan","asin","acos","atan","sinh","cosh","tanh","asinh","acosh","atanh"]]

count_length = lambda num, modulus, base_modulus : len(str(num).rstrip('0').lstrip('0')) + (1 + len(str(modulus)) if modulus != base_modulus else 0)

min_length = float("inf")
min_choice = None
for modulus in range(2,10):
   for i in range(1,100000):
      num = i/100000.
      is_valid = True
      for fn in fns:
         val = hash(fn[1](num))%modulus%2
         if (val == 0 and fn[0][0]=="a") or (val == 1 and fn[0][0]!="a"):
            is_valid = False
      if is_valid:
         length = count_length(num, modulus, 2)
         if length < min_length:
            min_length = length
            min_choice = (modulus,num)
print(min_choice)

min_length = float("inf")
min_choice = None
for modulus in range(3,10):
   for i in range(100000):
      num = i/100000.
      mapping = {}
      is_valid = True
      for fn in fns:
         fn_type = "sin" if "sin" in fn[0] else "cos" if "cos" in fn[0] else "tan"
         val = hash(fn[1](num))%modulus%3
         if val in mapping and mapping[val] != fn_type:
            is_valid = False
            break
         mapping[val] = fn_type
      if is_valid:
         length = count_length(num, modulus, 3)
         if length < min_length:
            min_length = length
            min_choice = (modulus, num, mapping)
print(min_choice)

min_length = float("inf")
min_choice = None
for modulus in range(2,10):
   for i in range(1,100000):
      num = i/100000.
      is_valid = True
      for fn in fns:
         val = hash(fn[1](num))%modulus%2
         if (val == 0 and fn[0][-1]=="a") or (val == 1 and fn[0][-1]!="a"):
            is_valid = False
      if is_valid:
         length = count_length(num, modulus, 2)
         if length < min_length:
            min_length = length
            min_choice = (modulus,num)
print(min_choice)

1
Harika ikinci cevap! Sihirli sayıları bulmak için kullandığınız programı paylaşır mısınız?
mbomb007

Teşekkürler! Çok güzel olmasa da cevabın sihirli sayılarını bulmak için kod ekledim.
nthistle

4

Python , 108 94 90 bayt

Giriş işlevinin sonucunu değer için tüm işlevlerin sonuçlarıyla karşılaştırır .2.

from cmath import*
lambda f:[w for w in globals()if w[-1]in'shn'and eval(w)(.2)==f(.2)][0]

Çevrimiçi deneyin

-14 byte Jonathan Allen
tarafından -4 byte Rod


Gerek yok re, sadece dilimleme ile gerekli olanları elde edin: lambda f,d=dir(cmath):[s for s in d[4:12]+d[22:]if eval("cmath."+s)(.2)==f(.2)][0](ithalat d=dir(cmath)daha önce gerçekleşmesi gerektiği için TIO üzerinde çalışmak üzere yeniden yazılmıştır, F=ancak sayılmaması için başlığın içinde olmalıdır).
Jonathan Allan,


Çok hoş! Thanks
mbomb007

4

Dyalog APL , 25 21 19 bayt

(8-(2○⍨8-⍳15)⍳⎕2)∘○

Çevrimiçi deneyin!

-3, H.PWiz
-2 sayesinde ngn sayesinde

Tüm gerekli trig işlevlerini (APL'de olan 1 2 3 5 6 7 ¯1 ¯2 ¯3 ¯5 ¯6 ¯7○2) artı bazı şeyleri (bu da geçer -7..7) bulur, hangisinin eşleştiğini bulur input○2ve "ile" çıktılar.num∘○


3

C (GCC) ile -lm, 374 346 324 bayt

Önerileriniz için Giacomo Garabello'ya teşekkürler.

Tel çekmeyi yapan orijinal makroma ek olarak token-yapıştırma yapmak için yardımcı bir makroyu kullanarak biraz daha fazla yer kazanmayı başardım.

Testlerde, sonuçların geçerliliğini doğrulamak için birkaç kütüphane dışı trig fonksiyonu kullandım. Kütüphane ile kütüphane olmayan işlevler arasındaki sonuçlar tam olarak aynı kayan nokta değeri olmadığından, eşitlik kullanmak yerine sonuçların farkını küçük bir değere compared karşılaştırdım.

#include <math.h>
#define q(f)f,#f,
#define _(f,g)q(f##sin##g)q(f##cos##g)q(f##tan##g)
#define p for(i=0;i<24;i+=2)
typedef double(*z)(double);*y[]={_(,)_(a,)_(,h)_(a,h)};i,x;*f(z g){int j[24]={0};char*c;double w;for(x=0;x++<9;)p!j[i]&isnan(w=((z)y[i])(x))-isnan(g(x))|fabs(w-g(x))>1E-9?j[i]=1:0;p!j[i]?c=y[i+1]:0;return c;}

Çevrimiçi deneyin!


14 baytı kaldırmayı başardım. TIO'da detayları bulabilirsiniz. Çevrimiçi deneyin!
Giacomo Garabello

Benden +1, ancak farklı bir strateji kullanarak bir alt 200 çözüm
buldum

3

JavaScript, 76 67 66 bayt

Güzel değil ama tavşan deliğinin aşağısına kadar uzağa gittim, bununla birkaç bira içmemeliydim . Nit'in çözümünden bağımsız olarak türetilmiştir.

b=>Object.getOwnPropertyNames(M=Math).find(x=>M[x](.8)+M==b(.8)+M)

Çevrimiçi deneyin


b=>Object.getOwnPropertyNames(M=Math).find(x=>M[x](.8)+M==b(.8)+M)? (rağmen karşılaştırmak için String dönüştürmek neden bilmiyorum)
l4m2

Bunu neden düşünmediğimi bilmiyorum. Teşekkürler, @ l4m2.
Shaggy,

@ l4m2 NaNEşit olarak karşılaştırmamız gerekir NaN, o yüzden ya öyle ya da öyle Object.is.
Neil,



2

JavaScript, 108 70 bayt

Asla Javascript'te golf oynamayı denemedim, bu yüzden burada geliştirilecek şeyler var.

t=>Object.getOwnPropertyNames(m=Math).find(f=>m[f](.9,0)+''==t(.9)+'')

Oldukça basittir, Mathprototip üzerindeki her fonksiyonu rasgele bir değere göre kontrol eder (0.9, diğer birçok değer işe yarar) ve kara kutu fonksiyonunun sonucuyla karşılaştırır.
Google Chrome'da test edildiğinde, kara kutu girişi işlevi, tetikleme işlevlerinden biri değilse kırılır.

Shaggy ve Neil sayesinde bir ton baytı kes.

const answer = t=>Object.getOwnPropertyNames(m=Math).find(f=>m[f](.9,0)+''==t(.9)+'');
const tests = [Math.sin, Math.cos, Math.tan, Math.asin, Math.acos, Math.atan, Math.sinh, Math.cosh, Math.tanh, Math.asinh, Math.acosh, Math.atanh];

tests.forEach(test => console.log(test + ' yields ' + answer(test)));


1
Çözüme çok benzer birkaç bira üzerinde çalışıyordum ama tam olarak çözemedim. 2 hızlı tasarruflar Ben spot: 0.3 -> .3ve atamak Mathiçin m içinde getOwnPropertyNames() .
Shaggy

1
Ben 71 bayt bu aşağı başardı: t=>Object.getOwnPropertyNames(m=Math).find(f=>m[f](.9,0)+''==t(.9)+'');. @Shaggy'nin de kullanıldığını fark ettim find. +''Bir dize sadece bir noktayı kontrol etmek zorunda anlamına karşılaştırmak yapar. ,0Bizi atlamak yapar Math.atan2.
Neil,

@Neil, gerektiği gibi görünmüyor ,0 : tio.run/##Lc6xDoMgEMbxvU/RMEFq2TvgG1jdjYknomLkzghp7dPTqEz/…
Shaggy

@Shaggy Sanırım uygulamaya bağlı; Firefox'ta, döndürdüğü diziden atan2önce gelir . acoshObject.getOwnPropertyNames
Neil,

Eğer biri merak ediyorsa, bu çözüm işe yarıyor çünkü ilk işlev dışı işlevi getOwnPropertyNamesMath.E ve tüm trig fonksiyonları bundan önce sayıyor.
Matt,

2

R , 75 bayt

function(b)Find(function(x)get(x)(1i)==b(1i),apropos('(sin|cos|tan)(h|$)'))

Çevrimiçi deneyin!

Şimdilik (R v3.5) çalışıyor.
Gelecekteki R sürümünde bu regex ile eşleşen bir işlev eklenecek, o zaman kim bilir: P

  • @Giuseppe sayesinde -2 bayt
  • @JayCe sayesinde -9 bayt
  • -2 bayt Findyerinefor

vay. Çok hoş! Bence -2 bayt için 1ide işe yarıyor -1i.
Giuseppe,

@Giuseppe: Test ettiğime ve işe yaramadığından emindim ... ama muhtemelen sadece hayal
gücümdü

çok hoş!
TIO'da

@JayCe: çevreyi pozisyona sokmak riskli ... mesela RStudio'da işe yaramaz ... Neyse ki her yerde, aynı bytecount ile nesneleri arayan başka bir işlev buldum :)
digEmAll

Sonunda ... GET kısaldı (77)
JayCe

1

HP 49G RPL, 10 baytlık program başlığı hariç 88.0 bayt

Karmaşık sayıları kullanarak başka bir çözüm! COMPLEX, APPROX modunda girin ve uygulayın. Yığındaki işlevi alır.

2. SWAP EVAL { SIN COS TAN ASIN ACOS ATAN SINH COSH TANH ASINH ACOSH ATANH }
DUP 1. << 2. SWAP EVAL >> DOLIST ROT - ABS 0. POS GET

(newlines önemli değil)

Sabit 2.0 için, tüm on iki trig fonksiyonu karmaşık düzlemde tanımlanmıştır, bu yüzden sadece on ikiyi değerlendiriyoruz ve hangisinin eşleştiğini görüyoruz. Bu sefer, yinelemeli çözüm, almak için gereken yığın karıştırmasından dolayı daha uzundur (111.5 bayt). RPL bildiğim kadarıyla erken bir döngüden ayrılmanıza izin vermiyor.


Büyük harf olarak geri gönderilmeleri durumunda, meydan okumayı değiştirdiğimde sorun değil.
Laikoni,

@JungHwanMin Onlar büyük harf. Yakalamak için teşekkürler! ->STR DUP SIZE 3 - " " " " IFTE XOR34,5 bayt ile küçük harf olarak değiştirilebilir . (sırasıyla 4 ve 3 boşluk olması gerekiyordu)
Jason,

1

Perl 6 , 39 bayt

{i.^methods.first({try $^a.(i)==.(i)})}

Çevrimiçi deneyin!

Şeylerin bakış açısına göre, iç gözlemini kullanan az sayıda biri. iişte her trig işlevi için değeri benzersiz olan karmaşık sayıdır, bu nedenle tüm yöntemleri yineleyerek eşleştirme yöntemini bulabilir ve örtük bir şekilde ismini verebiliriz. tryBazı (istenmeyen) yöntemleri farklı imzaya sahip olarak gereklidir.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.