Floating point and conversion optimization

I have the following formula

float mean = (r+b+g)/3/255.0f;

I want to speed it up. The following prerequisites exist

0<= mean <= 1  and 0 <= r,g,b <= 255 and r, g, b are unsigned chars

so if I try to use the fact that → 8 is like dividing by 256, and I use something like

float mean = (float)(((r+b+g)/3) >> 8);

this will always return 0. Is there a way to skip the expensive floating-point separation and still end up with a value between 0 and 1?

+3
source share
5 answers

Pre-convert your divisions into a constant with a short value:

a / 3 / 255

coincides with

a * (1 / (3 * 255))

so pre-compute:

const float AVERAGE_SCALE_FACTOR = 1.f / (3.f * 255.f)

then just

float mean = (r + g + b) * AVERAGE_SCALE_FACTOR;

since multiplication is usually much faster than division.

+16
source

, , - , 0 1. - 255 ?

+8

, ? mingw gcc 4.3 (x86). "gcc test.c -O2 -S -c -Wall"

:

float calc_mean(unsigned char r, unsigned char g, unsigned char b)
{
    return (r+b+g)/3/255.0f;
}

( . , , , ):

 movzbl 12(%ebp), %edx    ; edx = g
 movzbl 8(%ebp), %eax     ; eax = r
 addl %eax, %edx        ; edx = eax + edx
 movzbl 16(%ebp), %eax    ; eax = b
 addl %eax, %edx        ; edx = eax + edx
 movl $1431655766, %eax ; 
 imull %edx              ; edx *= a const
 flds LC0               ; put a const in the floating point reg
 pushl %edx              ; put edx on the stack
 fidivrl (%esp)            ; float reg /= top of stack

:

float calc_mean2(unsigned char r, unsigned char g, unsigned char b)
{
    const float AVERAGE_SCALE_FACTOR = 1.f / (3.f * 255.f);
    return (r+b+g) * AVERAGE_SCALE_FACTOR;
}

:

 movzbl 12(%ebp), %eax    
 movzbl 8(%ebp), %edx
 addl %edx, %eax
 movzbl 16(%ebp), %edx
 addl %edx, %eax
 flds LC2
 pushl %eax
 fimull (%esp)

, . -freciprocal-math fidivrl fimull, . .

, , - 18- , , - . , .

. , . !

+5

, . , , float. , . (r + g + b)/3/255.0f (r + g + b)/3.0f/255.0f, fimull.

+1

, C. Dub , , x86 x64, 1 2.

+1

Source: https://habr.com/ru/post/1716661/


All Articles