Жүзу нүктесінің операндаларына тапсырыс берудің қолайлы тәсілі бар ма?

Мысалы, менің келесі float a (мысалы, a = 0.5 ) <

6000.f * a * a;

Операндардың тәртібі қандай да бір айырмашылықты тудырады ма? Жазу керек пе?

6000.f * (a*a);

Немесе тіпті

float result = a*a;
result *= 6000.f;

Мен классикалық Әрбір компьютерлік ғалымның өзгермелі нүкте арифметикасы туралы білуі керек бірақ ештеңе таба алмады.

өзгермелі нүкте жұмысында операндаларға тапсырыс берудің оңтайлы тәсілі бар ма?

17
+1 нақты сұрау үшін.
қосылды автор R.., көзі

4 жауаптар

Бұл шын мәнінде құндылықтар мен мақсаттарға байланысты. Мысалы, егер a өте аз болса, a * a нөл болуы мүмкін, ал 6000.0 * a * a * a) * a ) әлі де нөлден шығуы мүмкін. Көтерілуден және ағып кетуден аулақ болу үшін, әдетте, қауымдастырылған заңды операндтардың логтарында қарама-қарсылыққа ие болған көбінесе көбінесе көбейтуді қолдануға болады. Екінші жағынан, квадраттың мәнін қайта пайдалану мүмкін болса, өнімділік себептері бойынша, бірінші кезекте квадрат жасау өте жақсы стратегия болуы мүмкін. Сіздің нөміріңіз ешқашан нөлге немесе шексіздікке өте жақын болмаса, толып кету/толып кету мәселелеріне қарағанда, дұрыстығы үшін маңызды болатын тағы бір мәселе болуы мүмкін: белгілі бір көбейтуге дәл жауап беруге кепілдік берілуі мүмкін, ал басқалары дөңгелектеуді талап етеді. Жалпы алғанда, сіз дөңгелектеу қадамдарының санын азайту арқылы ең дәл нәтижелер аласыз.

5
қосылды
+1 шынымен жақсы жауап.
қосылды автор ninjalj, көзі

Әдетте, жоқ.

Айтуынша, үлкен мәндермен бірнеше операция жасасаңыз, мүмкін олардың артықшылығы мен ассоциативтігі , алгоритм бұл анық көріну үшін мүмкіндік береді. Бұл, алайда, синтаксисті негізделіп қана қоймай, құндылықтарды алдын ала білуді қажет етеді.

3
қосылды
@MartyTPS: маңызды емес. Процессор бірдей нәтиже ретінде операцияларды сериялы түрде орындаған секілді есептейді.
қосылды автор Dietrich Epp, көзі
@MartyTPS: Сіз дұрыс емессіз. Тапсырыс сіздің бақылауыңызда. Компилятор/cpu өзгермелі нүкте әрекеттерін нәтижені өзгерте алатын кез-келген жолмен қайта реттей алмайды, және көпшілік мақсаттар үшін олар жай ғана өзгермелі нүктені қайта реттей алмайды дегенді білдіреді.
қосылды автор R.., көзі
@MartyTPS Сізге заманауи процессорлардағы Тапсырыссыз орындау туралы айтқан адам тәуелсіз нұсқаулар нұсқаулық ағынымен ерекшеленетін тәртіпте орындалуы мүмкін екенін білдіреді. Процессорлар тәуелді нұсқауларды қайта реттемейді. en.wikipedia.org/wiki/Out-of-order_execution
қосылды автор Pascal Cuoq, көзі
Сонымен қатар, қазіргі заманғы процессорларда сіз қандай операциялардың орындалуын немесе тіпті олар бірізді түрде орындалатындығын білмейміз.
қосылды автор MartyTPS, көзі
Назар аударыңыз, Дитрих. Тапсырысты өзгерту сұраныстың өзгеруіне байланысты болды. Бұл міндетті түрде сіздің бақылауыңызда болмайды, сондықтан ИӘ ИДІРІЛГЕН
қосылды автор MartyTPS, көзі

Оңтайлы жол шын мәнінде байланысты.

Ең алдымен, көбейту бөлуге қарағанда тезірек.

Егер сізге a = a/2; жазу керек болса, a = a * 0.5f; жазу керек. Сіздің компиляторыңыз, әдетте, егер нәтиже бірдей болса, бөлінуді тұрақты мәндермен көбейтуге ауыстыру үшін жеткілікті ақылды болады, бірақ, әрине, бұл айнымалылармен жасамайды.

Кейде бөлімдерді көбейтуге ауыстыру арқылы біраз оңтайландыруға болады, бірақ дәлдікте қиындықтар болуы мүмкін.

Кейбір басқа операциялар жылдамырақ, бірақ дәлірек анықталмаған болуы мүмкін. Мысал келтірейік.

float f = (a * 100000)/(b * 10);
float g = (a/b) * (100000/10);

Бұл математикалық баламалы, бірақ нәтиже әртүрлі болуы мүмкін. Біріншісі екі көбейтуді және бір бөлімді пайдаланады, екіншісі бір бөлімді және бір көбейтуді қолданады. Екі жағдайда да дәлме-дәл жоғалуы мүмкін, егер олар шағын мәндер бірінші жақсы жұмыс істейтін болса, егер олар үлкен мәндер болса, екіншіден жақсы жұмыс істейді

Сонда ... егер сіз бірнеше тұрақты және жылдамдықты қажет етсеңіз, топты біріктіріңіз.

float a = 6.3f * a * 2.0f * 3.1f;

Тек жазыңыз

a = a * (6.3f * 2.0f * 3.1f);

Кейбір компилятор жақсы оңтайландырады, кейбіреулерін аз оңтайландырады, бірақ екі жағдайда да барлық тұрақты мәндерді бірге сақтаудың ешқандай қатері жоқ.

Бұдан кейін біз процессорлар қалай жұмыс істейтіндігі туралы бірнеше сағат сөйлесуіміз керек. Тіпті интеллигенция сияқты бірдей отбасы ұрпақтар арасында өзгеше жұмыс істейді! Кейбір компиляторлар SSE нұсқауларын пайдаланады, ал басқалары жоқ. Кейбір процессор SSE2 қолдайды, кейбір SSE, тек кейбір MMX ... кейбір жүйеде FPU жоқ! Әрбір жүйе басқаларға қарағанда кейбір есептеулерді жақсартады, жалпыға бірдей нәрсе табу өте қиын.

You should Тек жазыңыз a readable code, clean and simple, without worryng too much about these unpredictable very low level optimizations.

Егер сіздің өрнегіңіз күрделі болып көрінсе, кейбір алгебра және \ немесе wolframalpha іздеу қозғалтқышына барып, оны сізге оңтайландыруды сұраңыз :)

Айтуынша, бір айнымалыны жариялауға және оның мазмұнын қайта-қайта алмастыруға міндетті емес екенін айтсаңыз, компилятор әдетте бұл жағдайда аз жұмсарта алады.

a = 5 + b;
a /= 2 * c;
a += 2 - c;
a *= 7;

Тек жазыңыз your expression avoiding this mess :)

a = ((5 + b)/(2 * c) + 2 - c) * 7;

About your specific example, 6000.f * a * a, Тек жазыңыз it as you write it, no need to change it; it is fine as it is.

3
қосылды
компиляторы нәтиже бірдей болмаса, бөлуді көбейтуге болмайды және бұл сирек. Бұл тек екеуінің өкілеттігі үшін ғана мүмкін. (Алайда, GCC бойынша -fast-math сияқты оңтайландырулар мүмкіндік береді.)
қосылды автор Dietrich Epp, көзі
Мен айтқанымдай, бұл тек екеуінің күшімен ғана болады. Сондықтан x/3 көбейтуге өзгерту мүмкін емес (егер x бүтін сан болса, әрине ...)
қосылды автор Dietrich Epp, көзі
Бөлу-> көбейту түрлендіруге арналған дәл сол себепті компилятор a * (6.3f * 2.0f * 3.1f) ішіне 6.3f * a * 2.0f * 3.1f , себебі бұл бірдей емес. Бұл өзгерісті жасайтын компилятор бағдарламашыдан опциямен шақырады, ол оңтайландыратын компилятор емес, бұл дұрыс компилятор. Бағдарламашы өзі айналдыруды өзі жасай алатынын және әдетте ол үшін өте жақсы екеніне келісемін, бірақ компилятор бұлай жасамайды, бұл оңтайландырудың болмауы.
қосылды автор Pascal Cuoq, көзі
Мен тұрақтылармен бөлісу туралы айтып тұрмын, микро-визуальды C бұл істеу қауіпті болмаса. Ол x/= 2 ауыстырады; x * = 0.5f; және бұл барлық тұрғыдан қауіпсіз.
қосылды автор Salvatore Previti, көзі
Әрине, екеуінің күші өзгермелі нүктесінде кодсыздықты жоғалту тәуекелі жоқ, ондықтың басқа түрі болмауы мүмкін, бірақ меніңше, бұл компиляторға және оңтайландыру параметрлерін белгілегеніңізге байланысты. Microsoft визуалды C-сында дәл немесе жылдам өзгермелі нүкте әрекеттерін алғыңыз келетін сұрақ бар.
қосылды автор Salvatore Previti, көзі

Шындығында, өзгермелі-нүктелік операциялардың кезектілігінде кумулятивтік қатені азайту үшін шынымен алгоритмдер бар. Олардың біреуі http://en.wikipedia.org/wiki/Kahan_summation_algorithm . Басқалары басқа операциялар үшін бар: http: //www.cs.cmu. edu/~ жер сілкінісі/байланысты/Priest.ps .

2
қосылды