Günah ve cos'u birlikte hesaplamanın en hızlı yolu nedir?


100

Bir değerin hem sinüsünü hem de eş sinüsünü birlikte hesaplamak istiyorum (örneğin bir rotasyon matrisi oluşturmak için). Tabii ki onları birbiri ardına ayrı ayrı hesaplayabilirim a = cos(x); b = sin(x);, ancak her iki değere de ihtiyaç duymanın daha hızlı bir yolu olup olmadığını merak ediyorum.

Düzenleme: Şimdiye kadarki cevapları özetlemek için:

  • Vlad ,FSINCOSikisini de hesaplayanasm komutuolduğunu söyledi (neredeyseFSINtek başınabir çağrı ile aynı zamanda)

  • Gibi Chi fark bu optimizasyon bazen zaten (optimizasyon bayrakları kullanılırken) derleyici tarafından yapılır.

  • caf , çalıştığınısincosvesincosfmuhtemelen mevcut olduğunu ve sadece dahil edilerek doğrudan çağrılabileceğini belirtti.math.h

  • Bir taramalı tablo kullanmanın tanascius yaklaşımı tartışmalı olarak tartışılmaktadır. (Bununla birlikte, bilgisayarımda ve bir kıyaslama senaryosundasincos, 32-bit kayan noktalar için neredeyse aynı doğruluklaolduğundan 3 kat daha hızlı çalışır.)

  • Joel Goodwin , oldukça hızlı bir yaklaşım tekniğinin ilginç bir yaklaşımını oldukça iyi bir doğrulukla ilişkilendirdi (benim için bu, tablo aramasından daha hızlı)


1
Sin / cos'un yerel uygulaması hakkındaki şu soruya da bakın: stackoverflow.com/questions/1640595
Joel Goodwin

1
denemek sinx ~ x-x^3/6ve cosx~1-x^2/4yaklaşımları olarak Doğruluğundan daha hız veriyorsan. Doğruluğa daha fazla ağırlık verdikçe her iki seriye de terim ekleyebilirsiniz ( en.wikipedia.org/wiki/Taylor_series , trig taylor serisine aşağı kaydırın.) Bunun, farklı nzamanlar olan istediğiniz herhangi bir işlevi yaklaşık olarak tahmin etmenin genel bir yolu olduğunu unutmayın . Yani sinüsün ve kosinüsün size ait olduğu daha büyük bir fonksiyonunuz varsa, günah yerine ona yaklaşırsanız, cos bağımsız olarak çok daha büyük bir hızlanacaktır.
ldog

Bu, çok zayıf doğruluğu olan kötü bir tekniktir. Joel Goodwin'in gönderisine bakın. Taylor serisi aşağıda yayınlanmıştır. Lütfen cevap olarak gönderin.
Danvil

1
Gereksinimlerinize bağlıdır, eğer doğruluk istiyorsanız Taylor serisi, ancak bir noktaya yakın değerlere ihtiyacınız varsa iyi bir yaklaşım olacaktır , ardından Taylor serinizi 0 yerine yaklaşık olarak genişletin. Bu size yakın, ancak daha uzağa mükemmel bir doğruluk sağlayacaktır. sonuçlar kötüleşir. Verilen asnwer'a bakarken ve onu uzaktaki değerler için denerken muhtemelen doğruluğun berbat olduğunu düşündünüz . Bu cevap günah ile ilgili, çünkü 0 civarında genişledi.xx_0x_0x_00
ldog

Yanıtlar:


52

Modern Intel / AMD işlemciler, FSINCOSaynı anda sinüs ve kosinüs işlevlerini hesaplamak için talimatlara sahiptir . Güçlü bir optimizasyona ihtiyacınız varsa, belki onu kullanmalısınız.

İşte küçük bir örnek: http://home.broadpark.no/~alein/fsincos.html

İşte başka bir örnek (MSVC için): http://www.codeguru.com/forum/showthread.php?t=328669

İşte başka bir örnek (gcc ile): http://www.allegro.cc/forums/thread/588470

Umarım içlerinden biri yardımcı olur. (Bu talimatı kendim kullanmadım, üzgünüm.)

İşlemci düzeyinde desteklendikleri için, tablo aramalarından çok daha hızlı olmalarını bekliyorum.

Düzenleme:
WikipediaFSINCOS , 387 işlemciye eklendiğini öne sürüyor , bu yüzden onu desteklemeyen bir işlemci bulmanız çok zor.

Düzenleme:
Intel'in belgeleri , FSINCOSbunun yaklaşık 5 kat daha yavaş olduğunu belirtir FDIV(yani, kayan nokta bölme).

Düzenleme:
Lütfen tüm modern derleyicilerin sinüs ve kosinüs hesaplamasını bir çağrıya dönüştürmediğini unutmayın FSINCOS. Özellikle, VS 2008'im bu şekilde yapmadı.

Düzenleme:
İlk örnek bağlantı öldü, ancak Wayback Machine'de hala bir sürüm var .


1
@phkahler: Bu harika olurdu. Böyle bir optimizasyonun modern derleyiciler tarafından kullanılıp kullanılmadığını bilmiyorum.
Vlad

12
fsincosTalimat değil "oldukça hızlı". Intel'in kendi optimizasyon kılavuzu, son mikro mimarilerde 119 ila 250 döngü gerektirdiğini belirtir. Intel'in matematik kitaplığı (ICC ile dağıtılır), karşılaştırmalı olarak, x87 birimi yerine SSE kullanan bir yazılım uygulaması kullanarak ayrı ayrısin ve cos100 döngüden daha kısa sürede hesaplayabilir . Her ikisini de aynı anda hesaplayan benzer bir yazılım uygulaması daha da hızlı olabilir.
Stephen Canon

2
@Vlad: ICC matematik kitaplıkları açık kaynaklı değil ve onları yeniden dağıtmak için bir lisansım yok, bu yüzden derlemeyi gönderemiyorum. sinBununla birlikte, yararlanabilecekleri yerleşik bir hesaplama olmadığını söyleyebilirim ; herkesle aynı SSE talimatlarını kullanırlar. İkinci yorumunuza göre, hız fdivönemsizdir; Bir şeyi yapmanın iki yolu varsa ve biri diğerinden iki kat daha hızlıysa, tamamen ilgisiz bir göreve göre ne kadar uzun sürerse sürsün, yavaş olanı "hızlı" olarak adlandırmanın bir anlamı yoktur.
Stephen Canon

1
sinKitaplıklarındaki yazılım işlevi, tam çift hassasiyetli doğruluk sağlar. fsincosTalimat biraz daha hassasiyet (çift uzatılmış) sunar, ancak bu ekstra doğruluk uzakta aramak çoğu programlarda atılan sinonun sonucu genellikle sonradan aritmetik işlemlerin veya belleğe bir mağaza tarafından çifte hassasiyetle yuvarlanır de fonksiyonu. Çoğu durumda, pratik kullanım için aynı doğruluğu sağlarlar.
Stephen Canon

4
Ayrıca fsincosbunun kendi başına tam bir uygulama olmadığını da unutmayın ; bağımsız değişkeni fsincostalimat için geçerli girdi aralığına koymak için ek bir aralık azaltma adımına ihtiyacınız var . Kitaplık sinve cosişlevler, bu azaltmanın yanı sıra çekirdek hesaplamayı da içerir, bu nedenle listelediğim döngü zamanlamalarından daha da hızlıdırlar (karşılaştırma olarak).
Stephen Canon

39

Modern x86 işlemcilerin, tam olarak istediğiniz şeyi yapacak bir fsincos talimatı vardır - aynı anda hem günah hem de cos hesaplayın. İyi bir optimizasyon derleyicisi, aynı değer için sin ve cos hesaplayan kodu algılamalı ve bunu yürütmek için fsincos komutunu kullanmalıdır.

Bunun çalışması için derleyici bayraklarının biraz karıştırılması gerekiyordu, ancak:

$ gcc --version
i686-apple-darwin9-gcc-4.0.1 (GCC) 4.0.1 (Apple Inc. build 5488)
Copyright (C) 2005 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ cat main.c
#include <math.h> 

struct Sin_cos {double sin; double cos;};

struct Sin_cos fsincos(double val) {
  struct Sin_cos r;
  r.sin = sin(val);
  r.cos = cos(val);
  return r;
}

$ gcc -c -S -O3 -ffast-math -mfpmath=387 main.c -o main.s

$ cat main.s
    .text
    .align 4,0x90
.globl _fsincos
_fsincos:
    pushl   %ebp
    movl    %esp, %ebp
    fldl    12(%ebp)
    fsincos
    movl    8(%ebp), %eax
    fstpl   8(%eax)
    fstpl   (%eax)
    leave
    ret $4
    .subsections_via_symbols

Tada, fsincos talimatını kullanıyor!


Bu havalı! -Mfpmath = 387'nin ne yaptığını açıklayabilir misiniz? Ve MSVC ile de çalışıyor mu?
Danvil

1
Bunu unutmayın -ffast-mathve -mfpmathbazı durumlarda farklı sonuçlara yol açar.
Debilski

3
mfpmath = 387, gcc'yi SSE talimatları yerine x87 komutlarını kullanmaya zorlar. MSVC'nin benzer optimizasyonlara ve bayraklara sahip olduğundan şüpheleniyorum, ancak emin olmak için elimde MSVC yok. X87 komutlarını kullanmak diğer kodlardaki performansa büyük olasılıkla zarar verecektir, ancak Intel'in MKL'sini kullanmak için diğer cevabıma da bakmalısınız.
Chi

Cygwin'den benim eski gcc 3.4.4, fsinve fcos. :-(
Vlad

En yüksek optimizasyonların etkinleştirildiği Visual Studio 2008 ile denendi. 2 kütüphane işlevini çağırır __CIsinve __CIcos.
Vlad

13

Performansa ihtiyacınız olduğunda, önceden hesaplanmış bir sin / cos tablosu kullanabilirsiniz (Sözlük olarak saklanan bir tablo olacaktır). İhtiyacınız olan doğruluğa bağlıdır (belki masa büyük olabilir), ancak gerçekten hızlı olmalı.


Daha sonra girdi değerinin [0,2 * pi] ile eşlenmesi gerekir (veya ek kontrollerle daha küçük) ve bu fmod çağrısı performansı tüketir. Benim (muhtemelen yetersiz) uygulamamda, arama tablosu ile performans elde edemedim. Burada herhangi bir tavsiyen var mı?
Danvil

11
Önceden hesaplanmış bir tablo neredeyse kesinlikle çağırmaktan daha yavaş sinolacaktır çünkü önceden hesaplanmış tablo önbelleği çöpe atacaktır.
Andreas Brinck

1
Masanın ne kadar büyük olduğuna bağlı. 256 girişli bir tablo genellikle yeterince doğrudur ve yalnızca 1Kb kullanır ... çok kullanırsanız, uygulamanın geri kalan performansını olumsuz yönde etkilemeden önbelleğe takılmaz mı?
Bay Boy

@Danvil: Burada bir sinüs arama tablosu örneği en.wikipedia.org/wiki/Lookup_table#Computing_sines . Ancak, girdinizi de [0; 2pi] ile eşlediğinizi varsayar.
tanascius

@AndreasBrinck Ben o kadar ileri gitmezdim. Bağlıdır (TM). Modern önbellekler çok büyük ve arama tabloları küçük. Çoğunlukla, bellek düzenine biraz özen gösterirseniz, arama tablonuzun, hesaplamanızın geri kalanının önbellek kullanımında herhangi bir fark yaratması gerekmez. Arama tablosunun önbelleğin içine sığması, bu kadar hızlı olmasının nedenlerinden biridir. Mem düzenini tam olarak kontrol etmenin zor olduğu Java'da bile, arama tablolarıyla büyük performans kazandım.
Jarrod Smith

13

Teknik olarak, bunu karmaşık sayılar ve Euler Formülü kullanarak elde edersiniz . Böylece (C ++)

complex<double> res = exp(complex<double>(0, x));
// or equivalent
complex<double> res = polar<double>(1, x);
double sin_x = res.imag();
double cos_x = res.real();

tek adımda size sinüs ve kosinüs vermelidir. Bunun dahili olarak nasıl yapıldığı, kullanılan derleyici ve kitaplığın sorusudur. Bunu bu şekilde yapmak daha uzun sürebilir (ve olabilir) (çünkü Euler'in Formülü çoğunlukla kompleksi ve expkullanarak hesaplamak için kullanılır - ve tersi değil), ancak bazı teorik optimizasyonlar mümkün olabilir.sincos


Düzenle

<complex>GNU C ++ 4.2'nin başlıkları açık sinve cosiç hesaplamalarını kullanıyor polar, bu nedenle derleyici biraz sihir yapmadıkça orada optimizasyonlar için çok iyi görünmüyor ( Chi'nin cevabında yazılan -ffast-mathve -mfpmathanahtarlarına bakın ).


üzgünüm, ama Euler'in Formülü aslında size bir şeyi nasıl hesaplayacağınızı söylemiyor , sadece karmaşık üstelleri gerçek trigonometrik fonksiyonlarla ilişkilendiren bir kimlik (çok faydalı olsa da). Sinüs ve kosinüsü birlikte hesaplamanın faydaları vardır, ancak bunlar ortak alt ifadeleri içerir ve cevabınız bunu tartışmaz.
Jason S

12

Bunlardan birini hesaplayabilir ve ardından kimliği kullanabilirsiniz:

cos (x) 2 = 1 - günah (x) 2

ancak @tanascius'un dediği gibi, önceden hesaplanmış bir tablo gitmenin yoludur.


8
Ve bu yöntemi kullanmanın bir güç ve bir karekök hesaplamayı içerdiğini unutmayın, bu nedenle performans önemliyse, bunun aslında diğer tetikleme işlevini doğrudan hesaplamaktan daha hızlı olduğunu doğruladığınızdan emin olun.
Tyler McHenry

4
sqrt()genellikle donanımda optimize edilir, bu nedenle sin()veya daha hızlı olabilir cos(). Güç sadece kendi kendini çoğaltmadır, bu yüzden kullanmayın pow(). Donanım desteği olmadan çok hızlı bir şekilde makul derecede doğru karekök elde etmenin bazı püf noktaları vardır. Son olarak, bunlardan herhangi birini yapmadan önce profil oluşturduğunuzdan emin olun.
deft_code

12
√ (1 - cos ^ 2 x) 'in, özellikle x ~ 0 olduğunda, sin x'i doğrudan hesaplamaktan daha az doğru
olduğuna dikkat edin.

1
Küçük x için, y = sqrt (1-x * x) için Taylor serisi çok güzel. İlk 3 terimle iyi bir doğruluk elde edebilirsiniz ve yalnızca birkaç çarpma ve bir vardiya gerektirir. Sabit nokta kodunda kullandım.
phkahler

1
@phkahler: Sizin Taylor serisi geçerli değildir, çünkü ne zaman x ~ 0, cos x ~ 1.
kennytm

10

GNU C kitaplığını kullanıyorsanız, şunları yapabilirsiniz:

#define _GNU_SOURCE
#include <math.h>

ve her iki değeri birlikte hesaplayan sincos(), sincosf()ve sincosl()işlevlerinin bildirimlerini alacaksınız - muhtemelen hedef mimariniz için en hızlı şekilde.


8

Bu forum sayfasında, hızlı ve iyi tahminler bulmaya odaklanan çok ilginç şeyler var: http://www.devmaster.net/forums/showthread.php?t=5784

Sorumluluk Reddi: Bunlardan hiçbirini kendim kullanmadım.

Güncelleme 22 Şubat 2018: Wayback Machine şu anda orijinal sayfayı ziyaret etmenin tek yoludur: https://web.archive.org/web/20130927121234/http://devmaster.net/posts/9648/fast-and-accurate- sinüs-kosinüs


Bunu da denedim ve bana oldukça iyi bir performans verdi. Ancak günah ve cos bağımsız olarak hesaplanır.
Danvil

Bence bu sinüs / kosinüs hesaplaması, sinüs almaktan ve kosinüs elde etmek için karekök yaklaşımı kullanmaktan daha hızlı olacak, ancak bir test bunu doğrulayacaktır. Sinüs ve kosinüs arasındaki birincil ilişki bir fazdır; Bunu hesaba katarak faz kaydırmalı kosinüs çağrıları için hesapladığınız sinüs değerlerini yeniden kullanabilmeniz için kodlamak mümkün mü? (Bu biraz zor olabilir, ancak sormak zorunda kaldım)
Joel Goodwin

Doğrudan değil (tam olarak bunu soran soruya rağmen). X değerine sahip günah ve cos'a ihtiyacım var ve başka bir yerde tesadüfen x + pi / 2'yi hesaplayıp hesaplamadığımı
bilmemin bir yolu yok

Bunu oyunumda bir parçacık çemberi çizmek için kullandım. Sadece görsel bir efekt olduğu için, sonuç yeterince yakın ve performans gerçekten etkileyici.
Maxim Kamalov

Etkilenmedim; Chebyshev yaklaşımları genellikle belirli bir performans için size en yüksek doğruluğu verir.
Jason S

7

Caf'in belirttiği gibi birçok C matematik kütüphanesinde zaten sincos () bulunur. Dikkate değer istisna MSVC'dir.

  • Sun, en az 1987'den beri sinco'lara () sahiptir (yirmi üç yıldır; basılı bir man sayfam var)
  • HPUX 11, 1997'de vardı (ancak HPUX 10.20'de değil)
  • 2.1 sürümünde glibc'ye eklendi (Şubat 1999)
  • Yerleşik bir gcc 3.4 (2004), __builtin_sincos () oldu.

Ve ilişkin taramalı, Eric S. Raymond Unix Programlama Sanatı (2004) (Bölüm 12) bu (zaman mevcut şu anda) kötü bir fikir açıkça diyor ki:

"Başka bir örnek, küçük tabloların ön hesaplanmasıdır - örneğin, bir 3B grafik motorundaki dönüşleri optimize etmek için derece derece bir günah (x) tablosu, modern bir makinede 365 × 4 bayt alacaktır. İşlemciler, önbelleğe alma talebinde bulunmak için bellekten yeterince hızlı olmadan önce Bu bariz bir hız optimizasyonuydu. Günümüzde, tablonun neden olduğu ek önbellek kayıplarının yüzdesini ödemek yerine her seferinde yeniden hesaplamak daha hızlı olabilir.

"Ancak gelecekte, önbellekler büyüdükçe bu durum tekrar dönebilir. Daha genel olarak, çoğu optimizasyon geçicidir ve maliyet oranları değiştikçe kolayca kötümserleştirmelere dönüşebilir. Bilmenin tek yolu ölçmek ve görmektir." ( Unix Programlama Sanatından )

Ancak yukarıdaki tartışmadan yola çıkarsak, herkes aynı fikirde değil.


10
"365 x 4 bayt". Artık yılları hesaba katmanız gerekir, yani bu aslında 365.25 x 4 bayt olmalıdır. Ya da belki bir dünya yılındaki gün sayısı yerine bir çemberdeki derece sayısını kullanmak istemiştir.
Ponkadoodle

@Wallacoloo: Güzel gözlem. Özledim Ancak hata orijinaldedir .
Joseph Quinsey

LOL. Artı, o bölgedeki bilgisayar oyunlarının çoğunda sadece sınırlı sayıda açıya ihtiyacınız olacağı gerçeğini de ihmal ediyor . Olası açıları biliyorsanız, önbellek kaçırma yoktur. Tam olarak bu durumda tabloları kullanır fsincosve diğerleri için (CPU talimatı!) Denerdim. Genellikle büyük bir tablodan günah ve cos enterpolasyonu kadar hızlıdır.
Erich Schubert

5

Arama tablolarının bu sorun için mutlaka iyi bir fikir olduğuna inanmıyorum. Doğruluk gereksinimleriniz çok düşük olmadığı sürece, tablonun çok büyük olması gerekir. Ve modern CPU'lar, ana bellekten bir değer getirilirken çok fazla hesaplama yapabilir. Bu, argümanla (benim bile değil) doğru bir şekilde cevaplanabilecek, verileri test edip ölçebilecek ve dikkate alabilecek sorulardan biri değil.

Ancak AMD'nin ACML'si ve Intel'in MKL'si gibi kütüphanelerde bulabileceğiniz SinCos'un hızlı uygulamalarına bakacağım.


3

Ticari bir ürün kullanmak istiyorsanız ve aynı anda bir dizi sin / cos hesaplaması yapıyorsanız (böylece vektörel fonksiyonları kullanabilirsiniz), Intel'in Math Kernel Kitaplığına göz atmalısınız .

Bu bir var SinCos işlevi

Bu belgelere göre, yüksek doğruluk modunda core 2 duo'da ortalama 13.08 saat / öğe alıyor, ki bu fsincos'tan bile daha hızlı olacak.


1
Benzer şekilde, OSX'te Accelerate.framework kullanılabilir vvsincosveya buradan kullanılabilir vvsincosf. AMD'nin vektör kütüphanesinde de benzer işlevlere sahip olduğuna inanıyorum.
Stephen Canon


2

Performans bu tür bir şey için kritik olduğunda, bir arama tablosu sunmak alışılmadık bir durum değildir.


2

Yaratıcı bir yaklaşım için Taylor serisini genişletmeye ne dersiniz? Benzer terimleri olduğundan, aşağıdaki sözde bir şey yapabilirsiniz:

numerator = x
denominator = 1
sine = x
cosine = 1
op = -1
fact = 1

while (not enough precision) {
    fact++
    denominator *= fact
    numerator *= x

    cosine += op * numerator / denominator

    fact++
    denominator *= fact
    numerator *= x

    sine += op * numerator / denominator

    op *= -1
}

Bu, şöyle bir şey yaptığınız anlamına gelir: günah ve kosinüs için x ve 1'den başlayarak, kalıbı takip edin - x ^ 2 / 2'yi çıkarın! kosinüsten, x ^ 3 / 3'ü çıkarın! sinüsten x ^ 4/4 ekleyin! kosinüs için x ^ 5/5 ekleyin! sinüs ...

Bunun performans olup olmayacağı konusunda hiçbir fikrim yok. Dahili sin () ve cos () 'nin size verdiğinden daha az kesinliğe ihtiyacınız varsa, bu bir seçenek olabilir.


Aslında i-sinüs uzatma faktörü, kosinüs uzatma faktörünün x / i katıdır. Ama Taylor serisini kullanmanın gerçekten hızlı olduğundan şüpheliyim ...
Danvil

1
Chebyshev, polinom fonksiyon yaklaşımı için Taylor'dan çok daha iyidir. Taylor yaklaşımını kullanmayın.
Timmmm

Burada bir sürü sayısal hata var; hem pay hem de payda hızla büyür ve bu da kayan nokta hatalarına yol açar. "Yeterli hassasiyetin" ne olduğuna ve bunu nasıl hesaplayacağınıza nasıl karar vereceğinizi söylememe gerek yok. Taylor yaklaşımı, mahallede tek bir nokta etrafında iyidir; bu noktadan sonra hızla yanlış hale gelirler ve çok sayıda terim gerektirirler, bu nedenle Timmmm'in Chebyshev yaklaşımı hakkındaki önerisi (belirli bir aralıkta iyi tahminler yaratır) iyi bir fikirdir.
Jason S

2

CEPHES kütüphanesinde oldukça hızlı olabilen güzel bir çözüm var ve biraz daha fazla / daha az CPU süresi için doğruluğu oldukça esnek bir şekilde ekleyebilir / kaldırabilirsiniz.

Cos (x) ve sin (x) 'in exp (ix)' in gerçek ve hayali kısımları olduğunu unutmayın. Bu yüzden ikisini birden elde etmek için exp (ix) hesaplamak istiyoruz. 0 ile 2pi arasındaki bazı ayrık y değerleri için exp (iy) 'i önceden hesaplıyoruz. X'i [0, 2pi) aralığına kaydırıyoruz. Daha sonra x'e en yakın
y'yi seçip exp (ix) = exp (iy + (ix-iy)) = exp (iy) exp (i (xy)) yazıyoruz.

Arama tablosundan exp (iy) alıyoruz. Ve | xy | küçüktür (y-değerleri arasındaki mesafenin en fazla yarısı), Taylor serisi sadece birkaç terimle güzelce yakınsar, bu yüzden bunu exp (i (xy)) için kullanıyoruz. Ve sonra exp (ix) elde etmek için karmaşık bir çarpmaya ihtiyacımız var.

Bunun bir başka güzel özelliği de SSE kullanarak vektörleştirebilmenizdir.


2

CEPHES kütüphanesinden esinlenerek bir SSE vektörleştirilmiş uygulama sunan http://gruntthepeon.free.fr/ssemath/ adresine bir göz atmak isteyebilirsiniz . İyi bir doğruluğa (5e-8 düzeninde sin / cos'dan maksimum sapma) ve hıza (tek bir çağrı bazında fsincos'tan biraz daha iyi performans gösterir ve birden fazla değere göre açık bir kazanan) sahiptir.




0

İki işlev için arama tabloları bildirmeyi düşündünüz mü? Yine de sin (x) ve cos (x) 'i "hesaplamanız" gerekir, ancak yüksek derecede doğruluğa ihtiyacınız yoksa kesinlikle daha hızlı olacaktır.


0

MSVC derleyicisi (dahili) SSE2 işlevlerini kullanabilir

 ___libm_sse2_sincos_ (for x86)
 __libm_sse2_sincos_  (for x64)

optimize edilmiş yapılarda uygun derleyici bayrakları belirtilirse (minimum / O2 / arch: SSE2 / fp: hızlı). Bu işlevlerin isimleri, ayrı günah ve cos hesaplamadıklarını, ancak her ikisinin de "tek adımda" olduğunu ima ediyor gibi görünmektedir.

Örneğin:

void sincos(double const x, double & s, double & c)
{
  s = std::sin(x);
  c = std::cos(x);
}

/ Fp ile derleme (x86 için): hızlı:

movsd   xmm0, QWORD PTR _x$[esp-4]
call    ___libm_sse2_sincos_
mov     eax, DWORD PTR _s$[esp-4]
movsd   QWORD PTR [eax], xmm0
mov     eax, DWORD PTR _c$[esp-4]
shufpd  xmm0, xmm0, 1
movsd   QWORD PTR [eax], xmm0
ret     0

Derleme (x86 için) olmadan / fp: hızlı ama bunun yerine / fp: kesin (varsayılandır) ayrı sin ve cos çağırır:

movsd   xmm0, QWORD PTR _x$[esp-4]
call    __libm_sse2_sin_precise
mov     eax, DWORD PTR _s$[esp-4]
movsd   QWORD PTR [eax], xmm0
movsd   xmm0, QWORD PTR _x$[esp-4]
call    __libm_sse2_cos_precise
mov     eax, DWORD PTR _c$[esp-4]
movsd   QWORD PTR [eax], xmm0
ret     0

So / fp: fast, sincos optimizasyonu için zorunludur.

Ama lütfen unutmayın

___libm_sse2_sincos_

belki kadar kesin değil

__libm_sse2_sin_precise
__libm_sse2_cos_precise

adının sonunda eksik olan "kesin" nedeniyle.

En son MSVC 2019 derleyicisine ve uygun optimizasyonlara sahip "biraz" eski sistemimde (Intel Core 2 Duo E6750), kıyaslamam sincos çağrısının ayrı sin ve cos çağrılarından yaklaşık 2,4 kat daha hızlı olduğunu gösteriyor.

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.