O que a constante 0.0039215689 representa?

310

Eu continuo vendo essa constante aparecer em vários arquivos de cabeçalho de gráficos

0.0039215689

Parece ter algo a ver com cor, talvez?

Aqui está o primeiro hit no 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

O que esse número representa? Por que ninguém parece declarar isso como uma const?

Não consegui encontrar nada no Google que explicasse isso.

A paixão súbita
fonte
16
Existe alguma razão para o código fonte escrever isso em vez de (1.f/255)?
MM
53
Mmmm ... se houvesse alguma maneira de evitar números mágicos ....
Paul Draper
12
1/255 == 0.00(3921568627450980)parens significa repetição.
JFS
82
Com o seu número mágico seguinte, tente perguntar Wolfram Alpha
AakashM
12
seja qual for o motivo, o uso de um número mágico sem documentar seu objetivo não é muito legal
Isaac Rabinovitch 27/03

Respostas:

378

0.0039215689é aproximadamente igual a 1/255.

Como esse é o OpenGL, o desempenho é provavelmente importante. Portanto, é provavelmente seguro adivinhar que isso foi feito por razões de desempenho.

Multiplicar pela recíproca é mais rápido do que dividir repetidamente por 255.


Nota:

Se você está se perguntando por que essa micro-otimização não é deixada para o compilador, é porque é uma otimização de ponto flutuante insegura. Em outras palavras:

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

devido a erros de arredondamento de ponto flutuante.

Portanto, embora os compiladores modernos possam ser inteligentes o suficiente para fazer essa otimização, eles não podem fazê-lo, a menos que você os indique explicitamente por meio de um sinalizador do compilador.

Relacionado: Por que o GCC não otimiza a * a * a * a * a * a para (a * a * a) * (a * a * a)?

Mysticial
fonte
10
Na verdade, eu não sabia o que era quando o vi pela primeira vez. Mas, vendo como era usada, suspeitava que fosse a otimização de multiplicar por recíproca. Então verifiquei minha calculadora e com certeza - adivinhei certo.
Mysticial 24/03
55
Eu esperaria vê-lo escrito como a = b * (1.0f / 255); compiladores ainda fazem dobragem constante, não é?
Ilmari Karonen
9
@IlmariKaronen Sim, eles ainda fazem dobragem constante. Na verdade, é necessário para algumas coisas, como resoluções de modelo e coisas do tipo. Mas eu teria retirado isso como uma constante ou uma macro. Mas, ei, nem todo código está perfeitamente escrito. :)
Mysticial
5
@hippietrail Inicialmente, eu estava pensando a mesma coisa. Mas se você usar 256, ele será escalado a partir 0.0 - 0.996do desejado 0.0 - 1.0. ( 0.996 = 255/256onde 255é o maior número inteiro de 8 bits)
Mysticial 25/03
7
E, é claro, para responder minha própria pergunta, é porque os outros dois números não podem ser representados como flutuadores C padrão. O próximo número abaixo de 0.0039215689 é 0,0039215684.
precisa
79

Essa multiplicação 0.0039215689fconverte uma intensidade de cor com valor inteiro no intervalo de 0 a 255 em uma intensidade de cor com valor real no intervalo de 0 a 1.

Como Ilmari Karonen ressalta, mesmo que essa seja uma otimização, ela é muito mal expressa. Seria muito mais claro multiplicar por (1.0f/255).

David Heffernan
fonte
5
Ou talvez melhor, definido como constante?
Johny
9
@ Johny Certamente definido como uma constante. O ponto não é um valor mágico.
David Heffernan