Co oznacza stała 0,0039215689?

310

Ciągle widzę tę stałą wyskakującą w różnych plikach nagłówka grafiki

0.0039215689

Może to ma coś wspólnego z kolorem?

Oto pierwsze trafienie w Google :

void RDP_G_SETFOGCOLOR(void)
{
    Gfx.FogColor.R = _SHIFTR(w1, 24, 8) * 0.0039215689f;
    Gfx.FogColor.G = _SHIFTR(w1, 16, 8) * 0.0039215689f;
    Gfx.FogColor.B = _SHIFTR(w1, 8, 8) * 0.0039215689f;
    Gfx.FogColor.A = _SHIFTR(w1, 0, 8) * 0.0039215689f;
}

void RDP_G_SETBLENDCOLOR(void)
{
    Gfx.BlendColor.R = _SHIFTR(w1, 24, 8) * 0.0039215689f;
    Gfx.BlendColor.G = _SHIFTR(w1, 16, 8) * 0.0039215689f;
    Gfx.BlendColor.B = _SHIFTR(w1, 8, 8) * 0.0039215689f;
    Gfx.BlendColor.A = _SHIFTR(w1, 0, 8) * 0.0039215689f;

    if(OpenGL.Ext_FragmentProgram && (System.Options & BRDP_COMBINER)) {
        glProgramEnvParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 2, Gfx.BlendColor.R, Gfx.BlendColor.G, Gfx.BlendColor.B, Gfx.BlendColor.A);
    }
}

//...more like this

Co oznacza ten numer? Dlaczego nikt nie wydaje się deklarować tego jako const?

Nie mogłem znaleźć w Google niczego, co by to wyjaśniało.

zmiażdżyć
źródło
16
Czy jest jakiś powód, dla którego kod źródłowy mógłby to napisać zamiast (1.f/255)?
MM
53
Mmmm ... gdyby tylko istniał jakiś sposób na uniknięcie magicznych liczb ...
Paul Draper
12
1/255 == 0.00(3921568627450980)- parens oznacza powtórzenie.
jfs
82
Przy kolejnym magicznym numerze spróbuj spytać Wolfram Alpha
AakashM
12
bez względu na powód, używanie magicznej liczby bez dokumentowania jej celu jest bardzo nieciekawe
Isaac Rabinovitch

Odpowiedzi:

378

0.0039215689jest w przybliżeniu równy 1/255.

Ponieważ jest to OpenGL, wydajność jest prawdopodobnie ważna. Prawdopodobnie bezpiecznie zgadnąć, że zrobiono to ze względu na wydajność.

Mnożenie przez odwrotność jest szybsze niż wielokrotne dzielenie przez 255.


Dygresja:

Jeśli zastanawiasz się, dlaczego taka mikrooptymalizacja nie została pozostawiona kompilatorowi, to dlatego, że jest to niebezpieczna optymalizacja zmiennoprzecinkowa. Innymi słowy:

x / 255  !=  x * (1. / 255)

z powodu błędów zaokrąglania zmiennoprzecinkowego.

Chociaż współczesne kompilatory mogą być na tyle inteligentne, aby przeprowadzić tę optymalizację, nie mogą tego robić, chyba że wyraźnie powiesz im to za pomocą flagi kompilatora.

Powiązane: Dlaczego GCC nie optymalizuje * a * a * a * a * a do (a * a * a) * (a * a * a)?

Tajemniczy
źródło
10
Właściwie nie wiedziałem, co to jest, kiedy pierwszy raz to zobaczyłem. Ale widząc sposób, w jaki był używany, podejrzewałem, że była to optymalizacja wielokrotność po sobie. Więc sprawdziłem kalkulator i na pewno - zgadłem.
Mysticial
55
Spodziewałbym się, że zobaczę to jako a = b * (1.0f / 255); kompilatory wciąż wykonują ciągłe składanie, prawda?
Ilmari Karonen
9
@IlmariKaronen Tak, wciąż ciągle składają. Jest to faktycznie wymagane w przypadku niektórych rzeczy, takich jak rozdzielczości szablonów i tym podobne. Ale po prostu wyciągnę to jako stałą lub makro. Ale hej, nie cały kod jest doskonale napisany. :)
Mysticial
5
@hippietrail Początkowo zastanawiałem się nad tym samym. Ale jeśli użyjesz 256, skaluje się od 0.0 - 0.996pożądanego 0.0 - 1.0. ( 0.996 = 255/256gdzie 255jest największa 8-bitowa liczba całkowita)
Mysticial
7
I oczywiście, aby odpowiedzieć na moje pytanie, to dlatego, że dwóch pozostałych liczb nie można przedstawić jako standardowych liczb zmiennoprzecinkowych C. Kolejna liczba zmienna poniżej 0,0039215689 to 0,0039215684.
Daniel Waechter
79

To pomnożenie przez 0.0039215689fkonwertuje intensywność koloru o wartości całkowitej w zakresie od 0 do 255 na rzeczywistą intensywność koloru w zakresie od 0 do 1.

Jak podkreśla Ilmari Karonen, nawet jeśli jest to optymalizacja, jest ona raczej źle wyrażona. Mnożenie byłoby znacznie łatwiejsze (1.0f/255).

David Heffernan
źródło
5
A może lepiej, zdefiniowany jako stały?
Johny
9
@Johny Z pewnością zdefiniowany jako stała. Chodzi o to, że nie jest to magiczna wartość.
David Heffernan,