Is there any way to make these two functions run faster?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
// linear2sRGB is a sRGB encoder
func linear2sRGB(v float64) float64 {
if v <= 0.0031308 {
v *= 12.92
} else {
v = 1.055*math.Pow(v, 1/2.4) - 0.055
}
return v
}
// sRGB2linear is a sRGB decoder
func sRGB2linear(v float64) float64 {
if v <= 0.04045 {
v /= 12.92
} else {
v = math.Pow((v+0.055)/1.055, 2.4)
}
return v
}
|
Here’s a straightforward optimization: lookup table + linear interpolation:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
// Linear2sRGB converts linear inputs to sRGB space.
func Linear2sRGB(v float64) float64 {
i := v * lutSize
ifloor := int(i) & (lutSize - 1)
v0 := lin2sRGBLUT[ifloor]
v1 := lin2sRGBLUT[ifloor+1]
i -= float64(ifloor)
return v0*(1.0-i) + v1*i
}
func linear2sRGB(v float64) float64 {
if v <= 0.0031308 {
v *= 12.92
} else {
v = 1.055*math.Pow(v, 1/2.4) - 0.055
}
return v
}
const lutSize = 1024 // keep a power of 2
var lin2sRGBLUT [lutSize + 1]float64
func init() {
for i := range lin2sRGBLUT[:lutSize] {
lin2sRGBLUT[i] = linear2sRGB(float64(i) / lutSize)
}
lin2sRGBLUT[lutSize] = lin2sRGBLUT[lutSize-1]
}
func BenchmarkLinear2sRGB(b *testing.B) {
for i := 0; i < b.N; i++ {
for j := 0.0; j <= 1.0; j += 0.01 {
convert.Linear2sRGB(j)
}
}
}
|
The benchmark shows approximately 98% runtime performance improvement after optimization.
1
2
|
name old time/op new time/op delta
Linear2sRGB-6 6.38µs ± 0% 0.14µs ± 0% -97.87% (p=0.000 n=10+8)
|
有什么办法能够让这两个函数跑得更快吗?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
// linear2sRGB is a sRGB encoder
func linear2sRGB(v float64) float64 {
if v <= 0.0031308 {
v *= 12.92
} else {
v = 1.055*math.Pow(v, 1/2.4) - 0.055
}
return v
}
// sRGB2linear is a sRGB decoder
func sRGB2linear(v float64) float64 {
if v <= 0.04045 {
v /= 12.92
} else {
v = math.Pow((v+0.055)/1.055, 2.4)
}
return v
}
|
这里介绍一个很平凡的优化方案: lookup table + 线性插值:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
// Linear2sRGB converts linear inputs to sRGB space.
func Linear2sRGB(v float64) float64 {
i := v * lutSize
ifloor := int(i) & (lutSize - 1)
v0 := lin2sRGBLUT[ifloor]
v1 := lin2sRGBLUT[ifloor+1]
i -= float64(ifloor)
return v0*(1.0-i) + v1*i
}
func linear2sRGB(v float64) float64 {
if v <= 0.0031308 {
v *= 12.92
} else {
v = 1.055*math.Pow(v, 1/2.4) - 0.055
}
return v
}
const lutSize = 1024 // keep a power of 2
var lin2sRGBLUT [lutSize + 1]float64
func init() {
for i := range lin2sRGBLUT[:lutSize] {
lin2sRGBLUT[i] = linear2sRGB(float64(i) / lutSize)
}
lin2sRGBLUT[lutSize] = lin2sRGBLUT[lutSize-1]
}
func BenchmarkLinear2sRGB(b *testing.B) {
for i := 0; i < b.N; i++ {
for j := 0.0; j <= 1.0; j += 0.01 {
convert.Linear2sRGB(j)
}
}
}
|
基准测试显示,优化后的运行时性能提升约为 98%。
1
2
|
name old time/op new time/op delta
Linear2sRGB-6 6.38µs ± 0% 0.14µs ± 0% -97.87% (p=0.000 n=10+8)
|