В книжке для этой строчки дан следующий код: Код (Text): mov edx,[width] imul edx,[height] mov eax,edx sar eax,31;зачем тут два сдвига я не понимаю shr eax,31 lea eax,[eax+edx+1] sar eax;тут видимо имеется ввиду sar eax,1 Переменные и результат имею тип int, компилятор который такое генерит не указан. А меня интересует куда должно выполняться округление по стандарту, и как должен выглядеть дизассемблированный код?
Black_mirror (число).5 математики округляют к ближайшему чётному, бухгалтеры - строго вверх, программисты графических интерфейсов - почти всегда вниз (отбрасывают дробную часть), т.к. быстрее. Если заведомо известно, что одно из значений чётное, отдельные источники рекомендовали сначала разделить чётное на 2 сдвигом, и только потом умножать. Есть ли сейчас от этого фокуса какая-нибудь польза - не знаю.
CyberManiac Здесь округляется уже произведение, но куда именно я совсем не понимаю, у меня получается, что произведение делится и округляется так: 7FFFFFFFh -> C0000000h;потому что sar 7FFFFFFEh -> 3FFFFFFFh 7FFFFFFDh -> 3FFFFFFFh .... 3 -> 2 2 -> 1 1 -> 1 0 -> 0 -1 -> 0 -2 -> 0 -3 -> -1 - такое я еще могу понять, но вот соседние строки ни в какие ворота не лезут -4 -> -1 ... 80000003h -> C0000002h 80000002h -> C0000002h 80000001h -> C0000001h 80000000h -> C0000001h
Код (Text): sar eax,31;зачем тут два сдвига я не понимаю shr eax,31 эквивалентно Код (Text): shr eax,31 Код округляет от нуля. Т.е. положительные в большую сторону, отрицательные в меньшую. По модулю в большую сторону. Получается: if(mul_rslt>=0) rslt=(mul_rslt+1)>>1; else rslt=(mul_rslt+2)>>1; // rslt=(mul_rslt>>1)+1
Да, я ошибся. Округляется к плюс бесконечности. Причём округляется - не совсем правильное слово. Положительные - округляются в большую сторону. Отрицательные тоже округляются к большему, с той только разницей что если число делится нацело, результат будет на единицу больше. Псевдокод примерно такой: Код (Text): if(x>=0) rslt=round_up(x/2); else { if(x % 2) rslt=round_up(x/2); // нечётное else rslt=x/2+1; // это странно как-то... } Да и вообще код странный какой-то. Откуда он? То что два сдвига там лишние (эквивалентны одному), это 100%.
Black_mirror очевидно, что один из них написал сам программист (т.к. используются int, то очевидно, что sar), второй же вставил компилятор, чтобы использовать в команде lea (но очевидно не додумался убрать, оптимизацию выключили, или этот случай не учитывается компилятором)
Неа Я тут недавно наткнулся чисто случайно. Код чисто шаблонный, и нужен для деления на степени двойки знаковых чисел. А для деления на 2 один сдвиг там получается лишний. Вот код который генерирует GCC для ARM: деление на 2 Код (Text): lsr r3, r0, #31 add r0, r3, r0 asr r0, r0, #1 деление на 4 Код (Text): asr r3, r0, #31 lsr r3, r3, #30 add r0, r3, r0 asr r0, r0, #2 На х86 будет примерно так: деление на 2 Код (Text): mov ebx, eax shr ebx, 31 add eax, ebx sar eax, 1 деление на 4 Код (Text): mov ebx, eax sar ebx, 31 shr ebx, 30 add eax, ebx sar eax,2 Код очень похож на тот, который был в первом посте. Но в отличии от него округляет правильно