Apa yang diwakili oleh konstanta 0,0039215689?

310

Saya terus melihat ini muncul dalam berbagai file header grafis

0.0039215689

Sepertinya ada hubungannya dengan warna mungkin?

Inilah hit pertama di 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

Apa yang angka ini wakili? Mengapa tidak ada orang yang menyatakannya sebagai const?

Saya tidak dapat menemukan apa pun di Google yang menjelaskannya.

menghancurkan
sumber
16
Apakah ada alasan kode sumber akan menulis ini, bukan (1.f/255)?
MM
53
Mmmm ... kalau saja ada beberapa cara untuk menghindari angka ajaib ....
Paul Draper
12
1/255 == 0.00(3921568627450980)- parens berarti pengulangan.
jfs
82
Dengan nomor ajaib Anda berikutnya, coba tanyakan Wolfram Alpha
AakashM
12
apa pun alasannya, menggunakan angka ajaib tanpa mendokumentasikan tujuannya sangat tidak keren
Isaac Rabinovitch

Jawaban:

378

0.0039215689kira-kira sama dengan 1/255.

Melihat bahwa ini adalah OpenGL, kinerja mungkin penting. Jadi mungkin aman untuk menebak bahwa ini dilakukan karena alasan kinerja.

Mengalikan dengan timbal balik lebih cepat daripada berulang kali membagi dengan 255.


Catatan samping:

Jika Anda bertanya-tanya mengapa optimasi mikro seperti itu tidak diserahkan kepada kompiler, itu karena itu adalah optimasi floating-point yang tidak aman. Dengan kata lain:

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

karena kesalahan pembulatan floating-point.

Jadi, walaupun kompiler modern mungkin cukup pintar untuk melakukan optimasi ini, mereka tidak diperbolehkan melakukannya kecuali Anda secara eksplisit menyuruh mereka melalui flag kompiler.

Terkait: Mengapa GCC tidak mengoptimalkan a * a * a * a * a * a ke (a * a * a) * (a * a * a)?

Mistikal
sumber
10
Saya sebenarnya tidak tahu apa itu ketika pertama kali melihatnya. Tetapi melihat cara itu digunakan, saya curiga itu adalah optimasi multiply-by-resiprokal. Jadi saya memeriksa kalkulator saya dan cukup yakin - saya rasa benar.
Mysticial
55
Saya akan berharap melihatnya ditulis sebagai a = b * (1.0f / 255); kompiler masih melakukan pelipatan konstan, bukan?
Ilmari Karonen
9
@IlmariKaronen Ya, mereka masih melakukan pelipatan konstan. Ini sebenarnya diperlukan untuk beberapa hal seperti resolusi template dan semacamnya. Tapi saya akan menariknya sebagai konstanta atau makro. Tapi hei, tidak semua kode ditulis dengan sempurna. :)
Mysticial
5
@hippietrail Awalnya, saya bertanya-tanya hal yang sama. Tetapi jika Anda menggunakan 256, itu akan skala dari 0.0 - 0.996yang diinginkan 0.0 - 1.0. ( 0.996 = 255/256mana 255bilangan bulat 8-bit terbesar)
Mysticial
7
Dan tentu saja, untuk menjawab pertanyaan saya sendiri, itu karena dua angka lainnya tidak dapat direpresentasikan sebagai pelampung standar C. Float berikutnya di bawah 0,0039215689 adalah 0,0039215684.
Daniel Waechter
79

Penggandaan ini dengan 0.0039215689fmengubah intensitas warna bernilai integer dalam kisaran 0 hingga 255 ke intensitas warna bernilai nyata dalam kisaran 0 hingga 1.

Seperti yang Ilmari Karonen tunjukkan, bahkan jika ini adalah optimasi, itu adalah ekspresi yang agak buruk. Akan jauh lebih jelas untuk dikalikan dengan (1.0f/255).

David Heffernan
sumber
5
Atau mungkin lebih baik, didefinisikan sebagai konstanta?
Johny
9
@ Johnny Pasti didefinisikan sebagai konstanta. Intinya bukan nilai ajaib.
David Heffernan