Осы дәлме-дәл операцияның нәтижесі қалай дөңгелектенеді? [Немесе неге бұл бит 1 және 0 емес?]

Мен өте нақты жағдайларда біріктіре алмайтын функцияны оңтайландырудың тәртібі (Nelder-Mead алгоритмінің нұсқасы) бойынша жұмыс істеймін.

Мен a арасындағы float айнымалысы, оны a деп атайық, оны a және басқа b , ол одан біраз ғана ерекшеленеді.

Дәлірек айтқанда, әрбір айнымалылардың мәндері төмендегідей:

float a = 25.9735966f;//41CFC9ED
float b = 25.9735947f;//41CFC9EC

Енді a және b арасындағы a мәнін беруге тырысамын:

a = 0.5 * (a+b);

When I write this code in a test program, I get the result I want, namely 25.9735947. But in the debugger of my original library code I see that the value of a remains 25.9735966. I'm pretty certain that I have the same compiler flags on both programs. Is there any reason why this single-precision calculation would yield different results?

ЖАҢАРТУ

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

.loc 1 53 0 discriminator 2
movl    -60(%rbp), %eax
cltq
salq    $3, %rax
addq    -88(%rbp), %rax
movq    (%rax), %rax
movl    -44(%rbp), %edx
movslq  %edx, %rdx
salq    $2, %rdx
leaq    (%rax,%rdx), %rcx
movl    -44(%rbp), %eax
cltq
salq    $2, %rax
addq    -72(%rbp), %rax
movl    -60(%rbp), %edx
movslq  %edx, %rdx
salq    $3, %rdx
addq    -88(%rbp), %rdx
movq    (%rdx), %rdx
movl    -44(%rbp), %esi
movslq  %esi, %rsi
salq    $2, %rsi
addq    %rsi, %rdx
movss   (%rdx), %xmm1
movl    -52(%rbp), %edx
movslq  %edx, %rdx
salq    $3, %rdx
addq    -88(%rbp), %rdx
movq    (%rdx), %rdx
movl    -44(%rbp), %esi
movslq  %esi, %rsi
salq    $2, %rsi
addq    %rsi, %rdx
movss   (%rdx), %xmm0
addss   %xmm1, %xmm0
movss   .LC6(%rip), %xmm1
mulss   %xmm1, %xmm0
movss   %xmm0, (%rax)
movl    (%rax), %eax
movl    %eax, (%rcx)

БАҚЫЛАУ

Менің коды - Nelder-Mead кодын Сандық Рецепттерден ripoff нұсқасы. Бұзылған желі - бұл:

p[i][j]=psum[j]=0.5*(p[i][j]+p[ilo][j]);

Бұл жолда p [i] [j] == 25.9735966f және p [ilo] [j] == 25.9735947f . p [i] [j] ішіндегі нәтиже мәні 25.9735966f болып табылады.

5
@ lindelof: Жоқ, тек көбейту және көбейтудің дәлдігі маңызды емес, себебі 0.5 - екі күші.
қосылды автор R.., көзі
@Pascal мен де түсіндім. Мен бұл мәндердің тек кітапхана кодексінде өңделетініне 99,9% сенімдімін. Бірақ бұл туралы білу өте қиын еді.
қосылды автор lindelof, көзі
@Scott Жоқ Мен отладчиктан кітапхана кодын (не дәлірек айтқанда, кітапхананы пайдаланатын бағдарламаны) іске қосу дегенді білдіремін.
қосылды автор lindelof, көзі
@PascalCuoq осы сызық 53-жолда болса, онда ол .loc 1 53 0 discriminator 2 сөзін оқитын жолдан тікелей құрастыру кодының бөлімі бола ма?
қосылды автор lindelof, көзі
@DavidHeffernan Иә, бұл дұрыс. Мен a және b-дың алты көрінісіне қарадым. Бір ғана айырмашылық бар.
қосылды автор lindelof, көзі
@PascalCuoq Шығуды disassemble -ден мына жерге қойдым: ideone.com/jq59h . Бұл сызықты қамтитын бүкіл функция үшін жинақ, ол емес пе?
қосылды автор lindelof, көзі
Эй, күте тұрыңыз ... 0.5 - бұл қосарланған литерал, сондықтан бір операциядан бұрын барлық операция екі есе дәлдікпен жасалмауы керек.
қосылды автор lindelof, көзі
A және b арасында ешқандай сан жоқ екенін білесіз бе?
қосылды автор David Heffernan, көзі
Сіз «отладчик» деп айтқан кезде, сіз отладчик көмегімен мәндерді тексергенде немесе сіз әдетте басқаша жұмыс істеген кезде осы кітапхананың отладчик нұсқасын пайдалану арқылы әртүрлі нәтижелер шығарады дегенді білдіресіз бе?
қосылды автор Scott Hunter, көзі
Мен әлі түсініктеме бермеймін, бірақ 25.9735947 дұрыс тіпті нәтижесіне жақсырақ дөңгелектенеді, өйткені сізге айтып беруім керек емес.
қосылды автор Pascal Cuoq, көзі
Түпнұсқалық кодтан a = 0.5 * (a + b) үшін жинағын көруге кез-келген мүмкіндік бар ма? Кез-келген басқа кітапхана байланысы бар «пайдалы» дөңгелектеу режимін орнатуы мүмкін бе?
қосылды автор Pascal Cuoq, көзі
@ lindelof Сіз отладчикпен орындап жатқаныңызды айттыңыз ба? Бұл түзеткішті GDB деп есептесе немесе GDB сияқты бірдей пәрмендерді қолданады, жолдың алдында тоқтау нүктесін орнатыңыз және шақыруда «бөлшектеңіз» деп теріңіз.
қосылды автор Pascal Cuoq, көзі
Сізге қатысты берілген тапсырманың коды mulss нұсқауларының айналасында. Функцияда тек біреу бар, сондықтан ешқандай белгісіздік жоқ. xmm0 және xmm1 кодтары a және b қотарылады, одан кейін addss дегенге xmm0 қосылады. LC6 жапсырма болуы керек, онда тұрақты 0.5 сақталады, бірақ ол бүтін сан ретінде ұсынылуы мүмкін (1056964608). Бұл екі еселенген дөңгелектеу мүмкіндігін мүлде жоққа шығарады: қолданылған нұсқаулар SSE нұсқаулық жиынтығынан алынған дәлме-дәл нұсқаулар болып табылады.
қосылды автор Pascal Cuoq, көзі
Бұл stackoverflow.com/questions/7356741 адресін еске салады.
қосылды автор Mark Dickinson, көзі

1 жауаптар

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

  • round to nearest, and in case of equal distance: set the least significant bit to zero => 25.9735947f
  • round towards +INF => 25.9735966f
  • round towards 0 => 25.9735947f
  • round towards -INF => 25.9735947f

Осылайша, тек отладки ортаңызда «INF дейін дөңгелектеу режимі бар. Мен үшін басқа ешқандай түсінік жоқ.

2
қосылды
-fast-math сияқты сынған нәрселер туралы не деуге болады? Немесе аралық нәтиже жоғары/төменгі дәлдікпен есептелсе не істей аламыз?
қосылды автор R.., көзі