Skip to content

Instantly share code, notes, and snippets.

@enjalot
Created May 3, 2013 00:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save enjalot/5506427 to your computer and use it in GitHub Desktop.
Save enjalot/5506427 to your computer and use it in GitHub Desktop.
bitwize
{"description":"bitwize","endpoint":"","display":"svg","public":true,"require":[],"fileconfigs":{"inlet.js":{"default":true,"vim":false,"emacs":false,"fontSize":12},"style.css":{"default":true,"vim":false,"emacs":false,"fontSize":12},"_.md":{"default":true,"vim":false,"emacs":false,"fontSize":12},"config.json":{"default":true,"vim":false,"emacs":false,"fontSize":12},"number.js":{"default":true,"vim":false,"emacs":false,"fontSize":12}},"fullscreen":false,"play":true,"loop":true,"restart":false,"autoinit":true,"pause":true,"loop_type":"period","bv":false,"nclones":15,"clone_opacity":0.4,"duration":3000,"ease":"linear","dt":0.01,"thumbnail":"http://i.imgur.com/lEgFmGd.png"}
/*
This shows the bitwise operaionts "right shift" and "left shift"
We can see how a decimal number is represented as binary.
Notice how a right bit shift moves the binary numbers over by one (binary) digit.
This is kind of like dividing the number by 2 each shift (and rounding down).
What would happen if you shifted a decimal number to the right? it would be like
dividing by 10 and rounding down.
A javascript integer is made up of 32 bits, left shifting can push our binary past 32 bits,
which causes unexpected results.
We can also see the hex representation, which is spaced like the binary into bytes
(8-bits == byte)
For a lot of useful algorithms we break up our data into bytes and do
bitwise operations on those chunks of bytes. So it can be useful to see how
we can turn a number into bits and bytes and back again.
*/
var svg = d3.select("svg");
var NUMBER = 17678;
var maxbits = 32;
var nbits = NUMBER.toString(2).length;
var ng = svg.append("g")
.attr("transform", "translate(" + [tributary.sw - 239,64] + ")")
var rshift = svg.append("g")
.attr("transform", "translate(" + [tributary.sw - 661,276] + ")")
.append("text").classed("rshift", true)
.text(" >> " + 0)
var ng2 = svg.append("g")
.attr("transform", "translate(" + [tributary.sw - 239,229] + ")")
var lshift = svg.append("g")
.attr("transform", "translate(" + [tributary.sw - 661,455] + ")")
.append("text").classed("lshift", true)
.text(" << " + 0)
var ng3 = svg.append("g")
.attr("transform", "translate(" + [tributary.sw - 239,410] + ")")
tributary.numberForms(ng, NUMBER, maxbits)
tributary.run = function(g,t) {
var shift = Math.floor(t * (nbits+1));
tributary.numberForms(ng2, NUMBER >> shift, maxbits)
tributary.numberForms(ng3, NUMBER << shift, maxbits)
svg.select(".rshift").text(" >> " + shift)
svg.select(".lshift").text(" << " + shift)
}
tributary.loop_type = "pingpong";
var twoColor = d3.scale.ordinal()
.domain([0, 1])
.range(["#6CB8DB", "#63DACB"]);
var byteColor = d3.scale.linear()
.domain([0, 255])
.range(["#9B0000", "#FFFFFF"]);
tributary.numberForms = numberForms
function numberForms(group,n, maxbits) {
//if(!maxbits) maxbits = 128
//@params
// group: d3 selection to update our text
//display a number "n" in integer, hex, binary
//assumes positive integers
//TODO: sort out janky selection stuff to make more reusable.
group.selectAll("g.num").remove()
g = group.selectAll("g.num").data([0])
g.exit().remove()
var dy = 30;
genter = g.enter()
.append("g").classed("num", true)
genter.append("g").classed("int", true)
genter.append("g").classed("bin", true)
.attr("transform", "translate(" + [0, dy] + ")")
genter.append("g").classed("hex", true)
.attr("transform", "translate(" + [0,2.5*dy] + ")")
genter.append("g").classed("dec", true)
.attr("transform", "translate(" + [0,3.5*dy] + ")")
genter.append("g").classed("bytes", true)
.attr("transform", "translate(" + [0,3*dy - 10] + ")")
var inttext = g.select("g.int");
inttext.append("text")
//.text("decimal").attr("x", 10)
inttext.append("text").classed("number", true)
.text(n)
binaryVis(g.select("g.bin"),n,maxbits);
hexVis(g.select("g.hex"), n, maxbits);
decVis(g.select("g.dec"), n, maxbits);
//byteVis(g.select("g.bytes"), n, maxbits);
}
function binaryVis(g,n,maxbits) {
binwidth = 8.7;
binspace = 1.2
var binary = n.toString(2);
//we want to pad our
var bits = binary.length;
zeropadding = zeropad(binary.length, maxbits)
binary = zeropadding + binary;
//binary = splitNumber(binary, 8);
binary = splitNumber(binary, 1);
g.selectAll("rect.digit")
.data(binary)
.enter()
.append("rect").classed("digit", true)
.attr({
x: function(d,i) { return -(i+1) * (binwidth+binspace) - 5 * Math.floor(i / 8) },
y: 10,
width: binwidth,
height: 10
})
.style({
fill: function(d,i) { return ["#BD5D5D", "#D6B4B4"][+d] }
})
g.append("text")
.text("binary: " + bits + " bits used").attr("x", 10).attr("y", 10)
g.append("text").classed("number", true).attr("x", -5)
.selectAll("tspan.chunks")
.data(binary.reverse()).enter().append("tspan")
.text(function(d){ return " " + d })
//.style("fill", function(d,i) { return coloring(i%8, binary.length); })
.attr("dx", function(d,i) { return (i%8) ? 0 : 4})
}
function hexVis(g,n,maxbits) {
var hex = n.toString(16);
hex = zeropad(hex.length, maxbits/4) + hex;
hex = splitNumber(hex, 2)
var bytes = hex.length
g.append("text")
.text("hex: " + bytes + " bytes used").attr("x", 10)
g.append("text").classed("number", true).attr("x", "-0.5em")
.selectAll("tspan.chunks")
.data(hex.reverse()).enter().append("tspan").classed("chunks", true)
.text(function(d){ return " " + d.toUpperCase() })
.attr("dx", "0.6em")
.style("fill", function(d,i) { return coloring(i, hex.length); })
}
function byteVis(g,n,maxbits) {
var hex = n.toString(16);
hex = zeropad(hex.length, maxbits/4) + hex;
hex = splitNumber(hex, 2)
var bytes = hex.length;
var bytewidth = 16;
var bytespace = 9;
g.selectAll("rect.byte")
.data(hex.reverse())
.enter().append("rect").classed("byte", true)
.attr({
x: function(d,i) { return -(bytewidth + bytespace) * (i+1) },
y: 0,
width: bytewidth,
height: bytewidth,
fill: function(d,i) { return byteColor(parseInt(d,16)) }
})
}
function decVis(g,n,maxbits) {
var hex = n.toString(16);
hex = zeropad(hex.length, maxbits/4) + hex;
hex = splitNumber(hex, 2)
var bytes = hex.length
dec = [];
hex.forEach(function(h) {
var int = parseInt(h,16) + "";
int = zeropad(int.length, 3) + int
dec.push(int)
})
g.append("text")
.text("decimal: " + bytes + " bytes used").attr("x", 10)
g.append("text").classed("number", true)
.selectAll("tspan.chunks")
.data(dec.reverse()).enter().append("tspan").classed("chunks", true)
.text(function(d){ return " " + d })
.style("fill", function(d,i) { return coloring(i, hex.length); })
}
function zeropad(l, p) {
//given a number of l digits, give a string of 0s to pad with
//so that there is always a multiple of p digits
n = l % p;
if(n)
return d3.range(p - n).map(function() { return "0" }).join("")
return "";
}
function splitNumber(s, l) {
//given a number (represented as a string "s")
//split it into chunks of size l
var chunks = [];
var chunk = "";
for(var i = s.length; i--;) {
chunk = s[i] + chunk;
if(i % l === 0) {
chunks.push(chunk);
chunk = "";
}
}
return chunks
}
function coloring(i,n) {
var ind = (n-i) & 1;
return twoColor(ind);
}
#display {
background: #0A0C35;
}
g.num {
fill: #008A69
}
.num .int .number {
font-family: "Courier New";
text-anchor: end;
font-size: 28px;
fill: #00DA57
}
.num .hex .number {
font-family: "Courier New";
text-anchor: end;
font-size: 17px
}
.num .dec .number {
font-family: "Courier New";
text-anchor: end;
font-size: 17px
}
.num .bin .number {
fill: #54E6D4;
text-anchor: end;
font-size: 12px
}
.rshift,.lshift {
fill: #D86F6F;
font-size: 31px;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment