PDA

View Full Version : حرفه ای: گرفتن سینوس و کسینوس با صدا زدن sin یا cos



UfnCod3r
دوشنبه 04 شهریور 1392, 12:32 عصر
من می خوام سینوس و کسینوس ی زاویه رو بدست بیارم طوری که فقط sin یا cos رو صدا بزنم و بعد ی کار کنم بقیش بدست بیاد .
برا پرفرمنس بیشتر می خوام این کاراو کنم .
ممنون .


void SinCos(float angle, float& outSin, float& outCos)
{
outSin = sin(angle);
outCos = ?????????????
}

UfnCod3r
دوشنبه 04 شهریور 1392, 12:35 عصر
البته بجز استفاده از این فرمول

cos(a) == sqrt(1 - sin(a)^2))

omidshaman
دوشنبه 04 شهریور 1392, 13:07 عصر
باید از بسط تابع sin و cos استفاده کنی
http://upload.wikimedia.org/math/5/4/6/546ecab719ce73dfb34a7496c942972b.png
یعنی به جای بتوان 2 رسوندن مستقیم با استفاده از angle بسطشو بنویسی احتمالا سریع تر میشه:متفکر:
http://en.wikipedia.org/wiki/Cosine#Sine.2C_cosine.2C_and_tangent

hadi0x7c7
دوشنبه 04 شهریور 1392, 13:17 عصر
شاید این فرمولا به درد بخوره:


sin(x) = (e^(ix) - e^(-ix)) / 2i; // i is imaginary number
cos(x) = (e^(ix) + e^(-ix)) / 2; // i is imaginary number
البته متوجه سوالتون نشدم هنوز !

hadi0x7c7
دوشنبه 04 شهریور 1392, 13:19 عصر
باید از بسط تابع sin و cos استفاده کنی
http://upload.wikimedia.org/math/5/4/6/546ecab719ce73dfb34a7496c942972b.png
یعنی به جای بتوان 2 رسوندن مستقیم با استفاده از angle بسطشو بنویسی احتمالا سریع تر میشه:متفکر:
http://en.wikipedia.org/wiki/Cosine#Sine.2C_cosine.2C_and_tangent

کتاب خونه ها خودشون از این روش استفاده میکنن خیلی کارا تر !

omidshaman
دوشنبه 04 شهریور 1392, 13:36 عصر
خب میشه sin , cos زوایا از 1 تا 90 رو ریخت داخل یک فایل دفعه اولی که برنامه اجرا میشه توی وکتور دخیرشون کرد ازشون استفاده کرد. 90 به بعد هم که همونه فقط قرینه میشن.

UfnCod3r
دوشنبه 04 شهریور 1392, 13:43 عصر
نه اونا که کلا کند تر می کنه
من ی چی سریع می خوام + دقتش هم بالا باشه :متفکر:

مصطفی ساتکی
دوشنبه 04 شهریور 1392, 14:09 عصر
خب میشه sin , cos زوایا از 1 تا 90 رو ریخت داخل یک فایل دفعه اولی که برنامه اجرا میشه توی وکتور دخیرشون کرد ازشون استفاده کرد. 90 به بعد هم که همونه فقط قرینه میشن.
همیشه که resolution از 0 تا 90 نیست طرف ممکنه اعشاری هم بخاد که در این صورت LUT خیلی کند تر میشه. بهترین کار اینکه از FSINCOS استفاده کنید کلاکش از مجموع FSIN و FCOS کمتره
FSIN FCOS 17-97

FSINCOS 18-110

UfnCod3r
دوشنبه 04 شهریور 1392, 15:43 عصر
منطورت FSINCOS اسمبلی هست ؟
اونو قبلا تست کرده بودم 100 برابر کند از sin ,cos تو VC10 بود .:لبخند::متفکر:
قبلنا با همین روش LUT یکی نوشته بودم بد نبود الان نمی دونم کداش کجاس
سیستم ریخته بهم بزار به مغرم فشار بیارم ببینم می تونم دوباره بنویسم :متفکر:
درضمن من نمی خوام از LUT استفاده کنم دقت بالا می خوام اون یکمکی دقتش کمه + کلی فضا می گیره :ناراحت:

مصطفی ساتکی
دوشنبه 04 شهریور 1392, 15:45 عصر
منطورت FSINCOS اسمبلی هست ؟
اونو قبلا تست کرده بودم 100 برابر کند از sin ,cos تو VC10 بود .:لبخند::متفکر:
نه عزیز جان کلاک رو از روی مستندات intel براتون گذاشتم.

UfnCod3r
دوشنبه 04 شهریور 1392, 15:59 عصر
خب فکر کنم FSINCOS رو با FSIN, FCOS مقایسه کرده
شاید توابع sin, cos از اونا استفاده نمی کنن
حالا ی بار دیگم امتحان می کنم ببینم چی میشه :متفکر:
با LUT اینو نوشته بودم قبلا. خوبیش اینه که برحسب درجه هم راحت میشه گرفت بدون ضرب اضافی


#define _XSIN_COS_PRISISION 600
#define X_FLOORF32(x) (i32)((x) - (0.99999f * ((x) < 0.0f)))

typedef int i32;
typedef float f32;

f32* gMath_SinTable = nullptr;
f32* gMath_CosTable = nullptr;

void Math_Init()
{
gMath_SinTable = new f32[360*_XSIN_COS_PRISISION+1];
gMath_CosTable = new f32[360*_XSIN_COS_PRISISION+1];

f64 add = X3D::PI2 / 360.0 / _XSIN_COS_PRISISION;
for(i32 i = 0; i <= 360*_XSIN_COS_PRISISION; i++)
{
gMath_SinTable[i] = sin(i*add);
gMath_CosTable[i] = cos(i*add);
}
}

inline void SinCosDeg(f32 angle, f32* outSin, f32* outCos)
{
angle = angle - ((X_FLOORF32(angle * (1.0f/360.0f)))*360.0f);
i32 i = angle * _XSIN_COS_PRISISION;
*outSin = gMath_SinTable[i];
*outCos = gMath_CosTable[i];
}

inline void SinCosRad(f32 angle, f32* outSin, f32* outCos)
{
angle = angle - ((X_FLOORF32(angle * (1.0f/PI2)))*PI2);
i32 i = angle * (_XSIN_COS_PRISISION * RAD2DEG);
*outSin = gMath_SinTable[i];
*outCos = gMath_CosTable[i];
}

مصطفی ساتکی
دوشنبه 04 شهریور 1392, 16:53 عصر
من می خوام سینوس و کسینوس ی زاویه رو بدست بیارم طوری که فقط sin یا cos رو صدا بزنم و بعد ی کار کنم بقیش بدست بیاد .
برا پرفرمنس بیشتر می خوام این کاراو کنم .
ممنون .

[/CPP]
شما چون این سوال رو پرسیدی بودید گفتم از FSINCOS استفاده کنید این در بدترین شرایط داره 110 کلاک میبره و به صورت full resolution کار می کنه در ضمن throughput ش هم صفره. در ضمن کد شما هم زیاد شده قابلیت خواندن پایین تر اومده و قابلیت نگهداری افت performance هم داشتیم.
شما تو این کدی گذاشتید تعداد تقسیم ها تو برای یک بار محاسبه حساب کنید ضربدر Latency مربوطه و اگر هم پیوسته 2 تا ضرب با تقسیم داشته باشید throughput هم خواهید داشت .ببینید چند تا ضرب تقسیم دارید حتی 32 به 64 هم دارید .

UfnCod3r
دوشنبه 04 شهریور 1392, 19:03 عصر
این الان خوانایش بیشتره :متفکر: جملات اخرتون رو اصلا متوجه نشدم .:گیج:

#define _XSIN_COS_PRISISION 600

float* gMath_SinTable = nullptr;
float* gMath_CosTable = nullptr;

void Math_Init()
{
gMath_SinTable = new float[360*_XSIN_COS_PRISISION+1];
gMath_CosTable = new float[360*_XSIN_COS_PRISISION+1];

double add = 3.1415926538f / 360.0 / _XSIN_COS_PRISISION;
for(i32 i = 0; i <= 360*_XSIN_COS_PRISISION; i++)
{
gMath_SinTable[i] = sin(i*add);
gMath_CosTable[i] = cos(i*add);
}
}

inline void SinCosDeg(float angle, float* outSin, float* outCos)
{
angle = angle - ((floor(angle * 0.00277777f))*360.0f);
int i = angle * _XSIN_COS_PRISISION;
*outSin = gMath_SinTable[i];
*outCos = gMath_CosTable[i];
}

مصطفی ساتکی
دوشنبه 04 شهریور 1392, 23:00 عصر
ا جملات اخرتون رو اصلا متوجه نشدم .:گیج:


latancy به میزان کلاک instruction گفته میشه و throughput هم به میزان تاخیر گفته میشه که بعد از اجرای instruction بوجود میاد البته اگر نوع instruction ها یکسان باشه.

FastCode
دوشنبه 04 شهریور 1392, 23:26 عصر
اگر روشم خیلی کمتر از 0.0001 خطا داشته باشه قول میدید همدیگر رو نزنید؟(قول میدم حافظه رو هم حروم نکنم;فقط چند تا(نمیگم) ضرب و یک static_cast ه float->int32)
(کلا خیلی حال میکنم اولش بگم همتون دارید وقتتون رو حروم میکنید بعدش که قشنگ فکراتون رو کردید بیام راه حل درست رو بگم)
و منظورم هیچ کدوم از اینها نیست:
http://stackoverflow.com/questions/2683588/what-is-the-fastest-way-to-compute-sin-and-cos-together
فردا بعد از اینکه اینجا جواب دادم.اونجا هم جواب میدم.فعلا برید فکر کنید.
برای اینکه بدونید چی توی ذهنمه باید روی این سوالها کار کنید:
اول باید IEEE754 رو از حفظ باشید.
بعد اینکه چطوری میخوام از F(X + Y) = F(X) + Y * F'(X) استفاده کنم.
و چرا static_cast.چرا cast معمولی نه؟
و اینکه ضرب دوم یا سوم چیه؟

UfnCod3r
سه شنبه 05 شهریور 1392, 09:35 صبح
اره .:لبخند:
ببینم چی کار می کنی :تشویق::چشمک::لبخندساده:

brightening-eyes
سه شنبه 05 شهریور 1392, 12:41 عصر
اگه از هر دو تا شون استفاده کنی پروفورمنست میره بالاتر
میتونی angle, outsin, outcos رو همرو پوینتر به همون متغیر تعریف کنی و بعدش با دستورات مموری بهشون یه مقدار بدی و بعدش که فانکشن کارش تموم شدش با free کارشونو یه سره کنی

FastCode
سه شنبه 05 شهریور 1392, 14:01 عصر
اگه از هر دو تا شون استفاده کنی پروفورمنست میره بالاتر
میتونی angle, outsin, outcos رو همرو پوینتر به همون متغیر تعریف کنی و بعدش با دستورات مموری بهشون یه مقدار بدی و بعدش که فانکشن کارش تموم شدش با free کارشونو یه سره کنی
من نگرفتم چی شد.ولی free فقط یک مفهوم داره و اون هم اینه که کدتون چند هزار برابر از کل این صفحه بدتره.

UfnCod3r
سه شنبه 05 شهریور 1392, 14:20 عصر
نمی دونم چرا همه فضایی حرف می زنن :قهقهه::متفکر:

Desaghi
سه شنبه 05 شهریور 1392, 16:26 عصر
زاویه را بین 0 تا 90 بگیرید و مقدارشان را از قبل محاسبه کنید نه در زمان اجرا.
cos(x) = sin(90-x)

برای دقت بیشتر از برونیابی خطی برای زاویه های اعشاری استفاده کنید.



http://en.wikipedia.org/wiki/Lookup_table

FastCode
سه شنبه 05 شهریور 1392, 17:26 عصر
زاویه را بین 0 تا 90 بگیرید و مقدارشان را از قبل محاسبه کنید نه در زمان اجرا.
cos(x) = sin(90-x)

برای دقت بیشتر از میانیابی خطی برای زاویه های اعشاری استفاده کنید.



http://en.wikipedia.org/wiki/Lookup_table
دقیقا این معنی تقسیم و یه چیزی حدود ۲۰ تا ۴۰ تا Cycle رو نمیده؟

Desaghi
سه شنبه 05 شهریور 1392, 17:39 عصر
تقسیم شاید

فرمول برونیابی خطی که در پست های قبلی آورده شده که تقسیم ندارد!؟

Desaghi
سه شنبه 05 شهریور 1392, 18:09 عصر
برنامه

x = degree?
tab(0:90) = ... /* the sin */
x2 = [x] در اکسل =ROUND(x;0) در c ??
dx = x - x2
sin = tab(x2)
cos = tab(90-x2)
sin = sin + dx * cos
cos = cos - dx * sin

مشتق بر حسب رادیان باشد.

مصطفی ساتکی
چهارشنبه 06 شهریور 1392, 07:41 صبح
اگر روشم خیلی کمتر از 0.0001 خطا داشته باشه قول میدید همدیگر رو نزنید؟(قول میدم حافظه رو هم حروم نکنم;فقط چند تا(نمیگم) ضرب و یک static_cast ه float->int32)
(کلا خیلی حال میکنم اولش بگم همتون دارید وقتتون رو حروم میکنید بعدش که قشنگ فکراتون رو کردید بیام راه حل درست رو بگم)
و منظورم هیچ کدوم از اینها نیست:
http://stackoverflow.com/questions/2683588/what-is-the-fastest-way-to-compute-sin-and-cos-together
فردا بعد از اینکه اینجا جواب دادم.اونجا هم جواب میدم.فعلا برید فکر کنید.
برای اینکه بدونید چی توی ذهنمه باید روی این سوالها کار کنید:
اول باید IEEE754 رو از حفظ باشید.
بعد اینکه چطوری میخوام از F(X + Y) = F(X) + Y * F'(X) استفاده کنم.
و چرا static_cast.چرا cast معمولی نه؟
و اینکه ضرب دوم یا سوم چیه؟
چی شد این جواب شما؟ امروز همون فردایی که قولشو دادید و گفتید همه بچه های تالار دارند وقتشونو حروم می کنند (البته تو stack هم کسی اینطوری پست نمی زاره) با صحبتی که با دوستان شده همه منتظرند تا شما جواب بدید میخام کل off topic های این تاپیک رو پاک کنم.

UfnCod3r
چهارشنبه 06 شهریور 1392, 09:05 صبح
1 سال بعد ...
ّFastCode دادا پس این سینوس کسینوس چی شد :قهقهه::چشمک:
این ارسال رو هم بعدا پاک کنید :لبخند:

FastCode
چهارشنبه 06 شهریور 1392, 16:55 عصر
چی شد این جواب شما؟ امروز همون فردایی که قولشو دادید و گفتید همه بچه های تالار دارند وقتشونو حروم می کنند (البته تو stack هم کسی اینطوری پست نمی زاره) با صحبتی که با دوستان شده همه منتظرند تا شما جواب بدید میخام کل off topic های این تاپیک رو پاک کنم.
ببخشید.فراموش کردم.الان هم خیلی فرصت ندارم پس فقط توضیح میدم و هر موقع فرصت پیدا کردم کدش رو مینویسم.
http://upload.wikimedia.org/wikipedia/commons/thumb/d/d2/Float_example.svg/590px-Float_example.svg.png
این IEEE 754 sf32 ه.
اگر فقط oxponent های ۱۲۵ و ۱۲۶ و ۱۲۷ رو در نظر بگیریم دو سری exponent داریم.
و اگر فقط ۷ یا ۸ بیت سمت چپ fraction رو در نظر بگیریم 384 یا 768 تا عدد داریم.(مطمئن نیستم کافی باشه چون هنوز کد رو ننوشتم.بنابراین تست هم نکردم.)
num & 0x01FF8000
که برای هر کدوم 8 بایت نیاز داریم که میشه 3072 یا 6144
سینوس و کسینوس های این اعداد رو در این ارایه ذخیره میکنیم.


int id = static_cast<int>(number) & 0x01FF8000;
float delta = static_cast<float>(id) - number;
id >>= 15;
float prox_sin = valuetable[id]; //optimized to one instruction by compiler
float prox_cos = valuetable[id + 1];//

بعد از اینکه این کار رو کردیم میریم سراغ دقت.
علامت سینوس و کسینوس رو داریم.پس نیازی نیست براشون کاری بکنیم.وداریم:

float fine_sin = prox_sin + delta * prox_cos


اون شبی که بهش فکر میکردم خیلی قشنگتر میشد.سعی میکنم کاملش رو بنویسم ولی الان .قت ندارم.ببخشید.