admin管理员组文章数量:1277320
As part of a project I have a string of numbers between 0 and 3, for example:
2030000000000000000030000000000000000003333212111221121301
I want to pass this string through an URL, so I figured I could try using a bitfield since each number only uses a maximum of 2 bits each. I wrote the following functions in my class to convert such a string to and from an array of integers used as bitfields for the data:
makeBuildBitfield: function(build) {
var b = build.split('');
var f = [3, 0]; // the "3" is there for future purposes
var i = 1;
var j = 0;
for (var t in b) {
if (j < 14) {
f[i] |= b[t];
f[i] = f[i] << 2;
++j;
} else {
f[i] |= b[t];
++i;
f[i] = 0;
j = 0;
}
}
return f.join('.');
},
getBuildFromBitfield: function(bitfield) {
b = bitfield.split('.');
var ba = [];
for (var x = 1; x < b.length; ++x) { //start from 1 to skip the "3"
ba[x] = [];
var n = b[x];
for (var y = 14; y >= 0; --y) {
ba[x][y] = n & 3;
n = n >>> 2;
}
}
build = '';
for (var a in ba) build += ba[a].join('');
return build;
},
They do seem to be working, but... not quite. When i pass the string from my example at the start:
2030000000000000000030000000000000000003333212111221121301
I get the following output:
3.587202560.786432.4089.156916164
However, when I pass this to the function that is supposed to convert it back, it gives me this:
203000000000000000003000000000000000000333321021112211213010
Note the extra zeros in the second string. Now, I'm new to operating on bits and this is my first attempt at it, but I've searched around and read the articles I could find on the subject, and I've tried to write down on a sheet of paper the state of the bits as the loop progresses to try and understand what is going on, but I just can't seem to figure out why it goes wrong and what those extra zeros are doing there. Either my string->bitfield
function is off, or the other one, or quite possibly both. But I really can't figure it out, so does anyone have any suggestions as to how I could fix whatever it is that's going wrong?
Thanks in advance!
As part of a project I have a string of numbers between 0 and 3, for example:
2030000000000000000030000000000000000003333212111221121301
I want to pass this string through an URL, so I figured I could try using a bitfield since each number only uses a maximum of 2 bits each. I wrote the following functions in my class to convert such a string to and from an array of integers used as bitfields for the data:
makeBuildBitfield: function(build) {
var b = build.split('');
var f = [3, 0]; // the "3" is there for future purposes
var i = 1;
var j = 0;
for (var t in b) {
if (j < 14) {
f[i] |= b[t];
f[i] = f[i] << 2;
++j;
} else {
f[i] |= b[t];
++i;
f[i] = 0;
j = 0;
}
}
return f.join('.');
},
getBuildFromBitfield: function(bitfield) {
b = bitfield.split('.');
var ba = [];
for (var x = 1; x < b.length; ++x) { //start from 1 to skip the "3"
ba[x] = [];
var n = b[x];
for (var y = 14; y >= 0; --y) {
ba[x][y] = n & 3;
n = n >>> 2;
}
}
build = '';
for (var a in ba) build += ba[a].join('');
return build;
},
They do seem to be working, but... not quite. When i pass the string from my example at the start:
2030000000000000000030000000000000000003333212111221121301
I get the following output:
3.587202560.786432.4089.156916164
However, when I pass this to the function that is supposed to convert it back, it gives me this:
203000000000000000003000000000000000000333321021112211213010
Note the extra zeros in the second string. Now, I'm new to operating on bits and this is my first attempt at it, but I've searched around and read the articles I could find on the subject, and I've tried to write down on a sheet of paper the state of the bits as the loop progresses to try and understand what is going on, but I just can't seem to figure out why it goes wrong and what those extra zeros are doing there. Either my string->bitfield
function is off, or the other one, or quite possibly both. But I really can't figure it out, so does anyone have any suggestions as to how I could fix whatever it is that's going wrong?
Thanks in advance!
Share Improve this question edited Jul 26, 2010 at 5:48 abatishchev 100k88 gold badges301 silver badges442 bronze badges asked Jul 25, 2010 at 19:40 Martin WedvichMartin Wedvich 2,2662 gold badges23 silver badges42 bronze badges 2- in makebitbuildfield you have a conditional about size being 14, in the other you assume it will be size 14. I haven't looked too closely, but that may be a problem at some point. – James Black Commented Jul 25, 2010 at 19:46
- You're right, it did cause problems down the road. Thanks :) – Martin Wedvich Commented Jul 25, 2010 at 21:11
3 Answers
Reset to default 7Here's a nice short approach that shrinks the bitfields to base-36 strings. It would work with base-10 strings too, but this is a little more condensed. It also works with leading zeros in the bitfield.
function shrink (s) {
for (var p=0, l=s.length, r=''; p<l; p+=25) {
r+=parseInt('1'+s.substring(p,p+25),4).toString(36);
}
return r;
}
function expand (s) {
for (var p=0, l=s.length, r=''; p<l; p+=10) {
r+=parseInt(s.substring(p,p+10), 36).toString(4).substring(1);
}
return r;
}
Edit - I'm assuming your goal is to shrink the bitfield, send it through the url (a GET request), and then expand it on the other side. This will allow you to do that, although you won't be able to do anything useful with the shrunk data besides transport it and expand it.
Edit 2 - This is now a "no-dots" variation. Here's a test:
var bits = "0000000000000000000000000000000032222000" +
"0000000000000000000000000000000031111300" +
"0000000000000000000002111300000002111200" +
"0000000000000000000003111120000003111130" +
"0000000000000000000000021111200000111120" +
"0000000000000320000000000211112000311110" +
"0000000000002111123000000031111130011113" +
"0000000000000321111111230000311112031111" +
"0000000000000000032111111123002112200000" +
"0000000032223300000000021111112000000000" +
"0000000021111111112233000332130000000000" +
"0330000000033322111111111111003330000000" +
"2112000000000000000003222112001113000000" +
"2112000111111111111112222220001113000000" +
"2112000222222111111111111120001113000000" +
"2112000000000000000033222230001113000000" +
"2112003111111111111111111120001113000000" +
"2112000000000000000000000000001113000000" +
"2112333333333333333333333333331113000000" +
"2111111111111111111111111111111113000000" ;
var shrunk = shrink(bits);
// b33j9ynrb4b34c70cb9cb33j9ynrclf2iv9lsx6ocpgnayh8n4b33j9ys...
var restored = expand(shrunk);
alert ( "Worked: " + (bits===restored) + ", orig size: "
+ bits.length + ", shrunk size: " + shrunk.length);
// Worked: true, orig size: 800, shrunk size: 320
There are several problems:
Don't use the "for (var x in y)" type of loop when iterating over arrays. Always use an index.
The last thing added to the bitfield string won't always represent 15 digits from the original. The "get" function always assumes that each bitfield ponent has the same number of digits.
You've left out
var
in some of your local variable declarations.
Here's my version, which works on your sample input at least:
makeBuildBitfield: function(build) {
var b = build.split('');
var f = [3, 0]; // the "3" is there for future purposes
var i = 1, j = 0;;
for (var t = 0; t < b.length; ++t, ++j) {
if (j === 15) {
f[++i] = 0;
j = 0;
}
f[i] = (f[i] << 2) + (b[t] & 3);
}
f[0] = j === 0 ? 15 : j;
return f.join('.');
},
getBuildFromBitfield: function(bitfield) {
var b = bitfield.split('.');
var ba = [];
for (var x = 1; x < b.length; ++x) { //start from 1 to skip the "3"
ba[x] = [];
var n = b[x];
for (var y = (x === b.length - 1 ? parseInt(b[0], 10) : 15); --y >= 0; ) {
ba[x][y] = n & 3;
n = n >>> 2;
}
}
var build = '';
for (var a = 1; a < ba.length; ++a) {
build += ba[a].join('');
}
return build;
}
I stole your "f[0]" for the size of the last entry, but you could put the value anywhere.
Well since I already have some bitmap code already written, here's a solution using it.
Bitmap.js
function Bitmap (vals) {
this.arr = [];
this.length = 0;
if (vals) {
for (var i = vals.length - 1; i >= 0; --i) {
if (vals [i]) {
this.set (i);
}
else {
this.clear (i);
}
}
}
}
Bitmap.prototype = {
constructor: Bitmap
, toString: function () {
vals = [];
for (var i = this.length - 1; i >= 0; --i) {
vals [i] = this.get (i) ? "1" : "0";
}
return vals.join ("");
}
, clear: function (i) {
if (i >= this.length) {
this.length = i + 1;
}
var pos = i / 32 | 0;
this.arr [pos] = this.arr [pos] & ~(1 << i % 32);
}
, get: function (i) {
return (this.arr [Math.floor (i / 32 | 0)] & 1 << i % 32) > 0;
}
, serialize: function () {
var str = "";
for (var i = 0; i < this.arr.length; ++i) {
var num = this.arr [i];
str += num < 0
? (-num).toString (36) + Bitmap.NEGATIVE_DELIM
: num.toString (36) + Bitmap.POSITIVE_DELIM
;
}
var trailingLength = this.length % 32;
if (trailingLength == 0) {
trailingLength = 32;
}
if (this.length == 0) {
trailingLength = 0;
}
return str + trailingLength.toString (36);
}
, set: function (i) {
if (i >= this.length) {
this.length = i + 1;
}
var pos = i / 32 | 0;
this.arr [pos] = this.arr [pos] | 1 << i % 32;
}
, size: function () {
return this.length;
}
};
Bitmap.POSITIVE_DELIM = ".";
Bitmap.NEGATIVE_DELIM = "!"
Bitmap.deserialize = (function () {
var MATCH_REGEX = new RegExp (
"[A-Za-z0-9]+(?:"
+ Bitmap.POSITIVE_DELIM
+ "|"
+ Bitmap.NEGATIVE_DELIM
+ ")?"
, "g");
return function (str) {
var bm = new Bitmap ();
var arr = str.match (MATCH_REGEX);
var trailingLength = parseInt (arr.pop (), 36);
for (var i = 0; i < arr.length; ++i) {
var str = arr [i];
var sign = str.charAt (str.length - 1) == Bitmap.POSITIVE_DELIM ? 1 : -1;
bm.arr [i] = parseInt (str, 36) * sign;
}
bm.length = Math.max ((arr.length - 1) * 32 + trailingLength, 0);
return bm;
};
}) ();
Test.js
function toBits (numStr, numBitsToExtract) {
var numChars = numStr.split ("");
var bits = [];
for (var i = 0; i < numChars.length; ++i) {
var num = numChars [i] - 0;
for (var j = numBitsToExtract - 1; j >= 0; --j) {
bits.push (num & 1 << j ? 1 : 0);
}
}
return bits;
}
function fromBits (bitStr, numBitsToExtract) {
var bitChars = bitStr.split ("");
var nums = [];
for (var i = 0; i < bitChars.length; ) {
var num = 0;
for (var j = numBitsToExtract - 1; j >= 0; ++i, --j) {
num |= bitChars [i] - 0 << j;
}
nums.push (num);
}
return nums.join ("");
}
var numStr = "2030000000000000000030000000000000000003333212111221121301";
var bits = toBits (numStr, 2);
var serialized = new Bitmap (bits).serialize (); // "1d.lc.ou00e8!ci3a.k"
var recoveredNumStr = fromBits (Bitmap.deserialize (serialized).toString (), 2);
本文标签: bit fieldsUsing integers as bitfields in JavaScriptStack Overflow
版权声明:本文标题:bit fields - Using integers as bitfields in JavaScript - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741231425a2362177.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论