04
2020
11

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;
}

平时用不到,编程语言都实现了。遇到问题的时候,知识储备就发挥作用了,这种编码解码比单纯乘个系数做个平移,再取余,要好得多。



« 上一篇下一篇 »

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。