ieee754浮点数编码
用texture给GUP传参数,好多GPU不支持浮点数纹理,所以要自己实现浮点数的编码解码。
我们研究32位编码,和24位编码。
ieee754标准可以从网上搜索学习。
对于32位浮点数,1位表示正负,0位正,1为负;8位表示指数;23位表示小数。
详细内容参见:https://www.cnblogs.com/HDK2016/p/10506083.html
用js简单实现:
var floatBuffer = new Float32Array(1);
var uintBuffer = new Uint8Array(floatBuffer.buffer);
decode(0.15625);
decode(123.456);
decode(-123.456);
decode(3154.138916015625);
decode(768);
function decode(value){
floatBuffer.set([value]);
console.log(uintBuffer);
var r = uintBuffer[0];
var g = uintBuffer[1];
var b = uintBuffer[2];
var a = uintBuffer[3];
var bits = [];
for(var i = 0; i < 4; i++) {
var v = uintBuffer[3 - i];
var n = 128;
for(var j = 0; j < 8; j++) {
bits.push(Math.floor(v / n));
v = v % n;
n = n / 2;
}
}
var sign = bits[0];
var e = 0;
for(var i = 1; i < 9; i++) {
e = e * 2 + bits[i];
}
console.log(bits);
console.log(sign);
console.log(e);
e = e - 127
console.log(e);
var f = 1;
var m = 0.5;
for(var i = 9; i < 32; i++) {
var bs = bits[i];
f += bs * m;
m *= 0.5;
}
console.log(f);
var r = f * Math.pow(2, e) * (sign ? (-1): 1);
console.log(r);
console.log("--------------------");
console.log(value +" 解码后 " + r);
console.log("--------------------");
}GPU中解码,可以从gpu.js中提取,,如下。
// Here be dragons!
// DO NOT OPTIMIZE THIS CODE
// YOU WILL BREAK SOMETHING ON SOMEBODY\'S MACHINE
// LEAVE IT AS IT IS, LEST YOU WASTE YOUR OWN TIME
const vec2 MAGIC_VEC = vec2(1.0, -256.0);
const vec4 SCALE_FACTOR = vec4(1.0, 256.0, 65536.0, 0.0);
const vec4 SCALE_FACTOR_INV = vec4(1.0, 0.00390625, 0.0000152587890625, 0.0); // 1, 1/256, 1/65536
float decode32(vec4 texel) {
texel *= 255.0;
vec2 gte128;
gte128.x = texel.b >= 128.0 ? 1.0 : 0.0;
gte128.y = texel.a >= 128.0 ? 1.0 : 0.0;
float exponent = 2.0 * texel.a - 127.0 + dot(gte128, MAGIC_VEC);
float res = exp2(_round(exponent));
texel.b = texel.b - 128.0 * gte128.x;
res = dot(texel, SCALE_FACTOR) * exp2(_round(exponent-23.0)) + res;
res *= gte128.y * -2.0 + 1.0;
return res;
}对于24位。我们取1位作为符号位,7位作为指数位,16位作为小数位。(指数位不应该是7,可以计算一下,用多少合适,这里为了简单,取7)。
代码如下:
[0.15625, 123.456, -123.456, 3154.138916015625, 768, -768,2633.142857142857, 1.0, -1.0].forEach((value) => {
var a = encode(value);
console.log(value, a, decode(a));
});
function encode(value) {
var sign = value > 0 ? 0 : 1;
value = Math.abs(value);
var exponent = Math.floor(Math.log2(value));
var mantissa = value * Math.pow(2, -exponent) - 1.0;
exponent = (exponent + 63) % 128;
var r = exponent + 128 * sign;
mantissa *= 256;
var g = Math.floor(mantissa);
mantissa = mantissa % 1;
mantissa *= 256;
var b = Math.floor(mantissa);
return [r, g, b];
}
function decode(arr){
var r = arr[0];
var g = arr[1];
var b = arr[2];
var sign = r >= 128 ? 1 : 0;
var exponent = (r - sign * 128) - 63;
var mantissa = ((256 + g) * 256 + b) * Math.pow(2, -16);
var f = mantissa * Math.pow(2, exponent) * (1 - sign * 2);
return f;
}平时用不到,编程语言都实现了。遇到问题的时候,知识储备就发挥作用了,这种编码解码比单纯乘个系数做个平移,再取余,要好得多。