Что представляет собой постоянная 0,0039215689?

310

Я постоянно вижу эту константу, всплывающую в различных графических заголовочных файлах

0.0039215689

Кажется, это как-то связано с цветом?

Вот первый хит в 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

Что означает это число? Почему никто, кажется, не объявляет это как const?

Я не смог найти в Google ничего, что могло бы это объяснить.

раздавить
источник
16
Есть ли какая-то причина, по которой исходный код написал бы это вместо (1.f/255)?
MM
53
Мммм ... если бы был какой-то способ избежать магических чисел ...
Пол Дрейпер
12
1/255 == 0.00(3921568627450980)- Парены означают повторение.
Jfs
82
Со своим следующим магическим номером попробуйте спросить Wolfram Alpha
AakashM
12
по какой бы то ни было причине, использование магического числа без документирования его назначения очень не круто
Исаак Рабинович,

Ответы:

378

0.0039215689примерно равно 1/255.

Видя, что это OpenGL, производительность, вероятно, важна. Так что, вероятно, можно догадаться, что это было сделано из соображений производительности.

Умножение на обратное происходит быстрее, чем повторное деление на 255.


Примечание:

Если вам интересно, почему такая микрооптимизация не оставлена ​​на усмотрение компилятора, это потому, что это небезопасная оптимизация с плавающей запятой. Другими словами:

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

из-за ошибок округления с плавающей точкой.

Таким образом, хотя современные компиляторы могут быть достаточно умны, чтобы выполнить эту оптимизацию, им не разрешается делать это, если вы явно не скажете им об этом с помощью флага компилятора.

Связанный: Почему GCC не оптимизирует a * a * a * a * a * a к (a * a * a) * (a * a * a)?

Mysticial
источник
10
Я действительно не знал, что это было, когда я впервые увидел это. Но, видя, как он использовался, я подозревал, что это была оптимизация, умноженная на взаимность. Так что я проверил свой калькулятор и, конечно же, я догадался.
Мистика
55
Я бы ожидал увидеть это как a = b * (1.0f / 255); компиляторы все еще делают постоянное свертывание, не так ли?
Илмари Каронен,
9
@IlmariKaronen Да, они все еще делают постоянное сворачивание. На самом деле это требуется для некоторых вещей, таких как разрешения шаблонов и тому подобное. Но я бы просто вытащил это как константу или макрос. Но, эй, не весь код написан идеально. :)
Mysticial
5
@hippietrail Изначально мне было интересно то же самое. Но если вы используете 256, он будет масштабироваться 0.0 - 0.996вместо желаемого 0.0 - 1.0. ( 0.996 = 255/256где 255наибольшее 8-разрядное целое число)
Mysticial
7
И, конечно же, чтобы ответить на мой собственный вопрос, это потому, что два других числа не могут быть представлены как стандартные числа с плавающей запятой. Следующее значение ниже 0,0039215689 - 0,0039215684.
Даниэль Вахтер
79

Это умножение на 0.0039215689fпреобразует целочисленную интенсивность цвета в диапазоне от 0 до 255 в реальную интенсивность цвета в диапазоне от 0 до 1.

Как указывает Илмари Каронен, даже если это оптимизация, она довольно плохо выражена. Было бы намного яснее умножить на (1.0f/255).

Дэвид Хеффернан
источник
5
Или, может быть, лучше, определяется как константа?
Джонни
9
@Johny Определено как константа. Дело не в волшебной ценности.
Дэвид Хеффернан