Hamsters holds a great promise to my work. I work with matrices and vectors in JavaScript. Recently I stumbled upon the JS Multithreading library Hamsters and read through the introduction at GitHub. Unfortunately I cannot get the code to work right - usually I don't get any errors but I get wrong or missing results.... It is extremely important that I get correct results all the time, else I'll have to abandon this approach. Am sure you can help me figure what's wrong. See sample code below. The Vanilla output is perfectly what I expect but Hamsters doesn't actually return any results, else when/if it does I get erroneous ones e.g. 0.05681.324987324.602 or similar.
var vec = [0.19560742625827293, 0.5969056836197602, 0.7781011114598421, -1.4801188964351797e-16, 0];
try {
var i, dotprod = 0, cnt = vec.length;
for (i = 0; i < cnt; i+=1) {
dotprod += (vec[i] * vec[i]);
}
console.log("vanilla:" + dotprod);
var params = {'array': vec};
hamsters.run(params, function () {
var arr = params.array;
var dotprod = 0;
arr.forEach(function (item) {
dotprod += (item * item);
});
console.log("each-thread:" + dotprod);
rtn.data = dotprod;
}, function (output) {
console.log("threads:" + output);
}, hamsters.maxThreads, true, 'Float32');
} catch (err) {
console.log(err);
}
I've also tried the code below, with the realization that the 'aggregation' means that each thread appends it's subarray into the final output... Still the results are not reliable and even straight out wrong. I have tried it on a matrix this time. The single-threaded Vanilla version still does it perfectly right.
var matrix = [
[0.19560742625827293, 0.5969056836197602, 0.7781011114598421, -1.4801188964351797e-16, 0],
[0.19560742625827268, 0.5969056836197597, -0.7781011114598423, 0, -4.9920006143177403e-17],
[0.6420441782236752, -0.28992643646108446, -0.06100766058506449, 0, 0.7071067811865475],
[0.3705351281738152, 0.6896295583459146, 0.6221854956882503, 0, 9.114104478471581e-17]
];
var i;
for (i = 0; i < matrix.length; i += 1) {
try {
var j, dotprod = 0, matrix_row = matrix[i];
for (j = 0; j < matrix_row.length; j += 1) {
dotprod += (matrix_row[j] * matrix_row[j]);
}
console.log("Vanilla-output:" + dotprod);
var params = {'array': matrix_row};
hamsters.run(params, function () {
var arr = params.array;
var dotprod = [];
arr.forEach(function (item) {
dotprod.push(item * item);
});
//console.log("each-thread:" + dotprod);
rtn.data = dotprod;
}, function (results) {
var output = 0;
results.forEach(function (item) {
output += item;
});
console.log("Hamsters-output:" + output);
}, hamsters.maxThreads, true, 'Float32');
} catch (err) {
console.log(err);
}
}
Related
Please help....Tried executing the below mentioned function but web console always shows
TypeError: xml.location.forecast[j] is undefined
I was able to print the values in alert but the code is not giving output to the browser because of this error. Tried initializing j in different locations and used different increment methods.How can i get pass this TypeError
Meteogram.prototype.parseYrData = function () {
var meteogram = this,xml = this.xml,pointStart;
if (!xml) {
return this.error();
}
var j;
$.each(xml.location.forecast, function (i,forecast) {
j= Number(i)+1;
var oldto = xml.location.forecast[j]["#attributes"].iso8601;
var mettemp=parseInt(xml.location.forecast[i]["#attributes"].temperature, 10);
var from = xml.location.forecast[i]["#attributes"].iso8601;
var to = xml.location.forecast[j]["#attributes"].iso8601;
from = from.replace(/-/g, '/').replace('T', ' ');
from = Date.parse(from);
to = to.replace(/-/g, '/').replace('T', ' ');
to = Date.parse(to);
if (to > pointStart + 4 * 24 * 36e5) {
return;
}
if (i === 0) {
meteogram.resolution = to - from;
}
meteogram.temperatures.push({
x: from,
y: mettemp,
to: to,
index: i
});
if (i === 0) {
pointStart = (from + to) / 2;
}
});
this.smoothLine(this.temperatures);
this.createChart();
};
You are trying to access the element after the last one. You can check if there is the element pointed by j before proceeding:
Meteogram.prototype.parseYrData = function () {
var meteogram = this,
xml = this.xml,
pointStart;
if (!xml) {
return this.error();
}
var i = 0;
var j;
$.each(xml.location.forecast, function (i, forecast) {
j = Number(i) + 1;
if (!xml.location.forecast[j]) return;
var from = xml.location.forecast[i]["#attributes"].iso8601;
var to = xml.location.forecast[j]["#attributes"].iso8601;
});
};
I am working on a project that needs an excel like calculation engine in the browser. But, it doesn't need the grid UI.
Currently, I am able to do it by hiding the 'div' element of Handsontable. But, it isn't elegant. It is also a bit slow.
Is there a client side spreadsheet calculation library in javascript that does something like this?
x = [ [1, 2, "=A1+B1"],
[2, "=SUM(A1,A2"),3] ];
y = CalculateJS(x);
##############
y: [[1, 2, 3],
[2,3,3]]
I'm not aware of any (although I haven't really looked), but if you wish to implement your own, you could do something along these lines (heavily unoptimized, no error checking):
functions = {
SUM: function(args) {
var result = 0;
for (var i = 0; i < args.length; i++) {
result += parseInt(args[i]);
}
return result;
}
};
function get_cell(position) {
// This function returns the value of a cell at `position`
}
function parse_cell(position) {
cell = get_cell(position);
if (cell.length < 1 || cell[0] !== '=')
return cell;
return parse_token(cell.slice(1));
}
function parse_token(tok) {
tok = tok.trim();
if (tok.indexOf("(") < 0)
return parse_cell(tok);
var name = tok.slice(0, tok.indexOf("("));
if (!(name in functions)) {
return 0; // something better than this?
}
var arguments_tok = tok.slice(tok.indexOf("(") + 1);
var arguments = [];
while (true) {
var arg_end = arguments_tok.indexOf(",");
if (arg_end < 0) {
arg_end = arguments_tok.lastIndexOf(")");
if (arg_end < 0)
break;
}
if (arguments_tok.indexOf("(") >= 0 && (arguments_tok.indexOf("(") < arg_end)) {
var paren_amt = 1;
arg_end = arguments_tok.indexOf("(") + 1;
var end_tok = arguments_tok.slice(arguments_tok.indexOf("(") + 1);
while (true) {
if (paren_amt < 1) {
var last_index = end_tok.indexOf(",");
if (last_index < 0)
last_index = end_tok.indexOf(")");
arg_end += last_index;
end_tok = end_tok.slice(last_index);
break;
}
if (end_tok.indexOf("(") > 0 && (end_tok.indexOf("(") < end_tok.indexOf(")"))) {
paren_amt++;
arg_end += end_tok.indexOf("(") + 1;
end_tok = end_tok.slice(end_tok.indexOf("(") + 1);
} else {
arg_end += end_tok.indexOf(")") + 1;
end_tok = end_tok.slice(end_tok.indexOf(")") + 1);
paren_amt--;
}
}
}
arguments.push(parse_token(arguments_tok.slice(0, arg_end)));
arguments_tok = arguments_tok.slice(arg_end + 1);
}
return functions[name](arguments);
}
Hopefully this will give you a starting point!
To test in your browser, set get_cell to function get_cell(x) {return x;}, and then run parse_cell("=SUM(5,SUM(1,7,SUM(8,111)),7,8)"). It should result in 147 :)
I managed to do this using bacon.js. It accounts for cell interdependencies. As of now, it calculates values for javascript formula instead of excel formula by using an eval function. To make it work for excel formulae, all one has to do is replace eval with Handsontable's ruleJS library. I couldn't find a URI for that library... hence eval.
https://jsfiddle.net/sandeep_muthangi/3src81n3/56/
var mx = [[1, 2, "A1+A2"],
[2, "A2", "A3"]];
var output_reference_bus = {};
var re = /\$?[A-N]{1,2}\$?[1-9]{1,4}/ig
var alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split('');
function convertToCellRef(rows, cols) {
var alphabet_index = rows+1,
abet = "";
while (alphabet_index>0) {
abet = alphabet[alphabet_index%alphabet.length-1]+abet;
alphabet_index = Math.floor(alphabet_index/alphabet.length);
}
return abet+(cols+1).toString();
}
function getAllReferences(value) {
if (typeof value != "string")
return null;
var references = value.match(re)
if (references.length == 0)
return null;
return references;
}
function replaceReferences(equation, args) {
var index = 0;
return equation.replace(re, function(match, x, string) {
return args[index++];
});
}
//Assign an output bus to each cell
mx.forEach(function(row, row_index) {
row.forEach(function(cell, cell_index) {
output_reference_bus[convertToCellRef(row_index, cell_index)] = Bacon.Bus();
})
})
//assign input buses based on cell references... and calculate the result when there is a value on all input buses
mx.forEach(function(row, row_index) {
row.forEach(function(cell, cell_index) {
if ((all_refs = getAllReferences(cell)) != null) {
var result = Bacon.combineAsArray(output_reference_bus[all_refs[0]]);
for (i=1; i<all_refs.length; i++) {
result = Bacon.combineAsArray(result, output_reference_bus[all_refs[i]]);
}
result = result.map(function(data) {
return eval(replaceReferences(cell, data));
})
result.onValue(function(data) {
console.log(convertToCellRef(row_index, cell_index), data);
output_reference_bus[convertToCellRef(row_index, cell_index)].push(data);
});
}
else {
if (typeof cell != "string")
output_reference_bus[convertToCellRef(row_index, cell_index)].push(cell);
else
output_reference_bus[convertToCellRef(row_index, cell_index)].push(eval(cell));
}
})
})
output_reference_bus["A2"].push(20);
output_reference_bus["A1"].push(1);
output_reference_bus["A1"].push(50);
I'm fetching data from SharePoint using REST, and everything works just fine, except that I would like to count the times the same item appears.
This is the jQuery:
var url = "https:xxxxxxxx/_vti_bin/ListData.svc/RMSD_Tasks?$orderby=TypeOfIssueValue asc,StatusValue desc&$filter=StatusValue ne 'Completed'&groupby=TypeOfIssueValue/StatusValue";
var lastIssue = '';
$.getJSON(url, function (data) {
$('#totalCounter').text(data.d.results.length);
for (var i = 0; i < data.d.results.length; i++) {
var dateReceived = data.d.results[i].DateReceived;
dateReceived = new Date(parseInt(dateReceived.replace("/Date(", "").replace(")/", ""), 10)).toLocaleString('en-US', {
year: 'numeric',
month: 'numeric',
day: '2-digit'
});
var issue = data.d.results[i].TypeOfIssueValue;
console.log(data.d.results[i].TypeOfIssueValue);
if (issue != lastIssue) {
lastIssue = issue;
$('#myDataList').append('' + issue + '<span class="badge">' + issue.length + '</span>');
}
}
});
I need to count how many time a specific TypeOfIssueValue appears. When I see the console it shows exactly what I would like to add to me info:
I just added a issue.length in the badge were I want to insert the number for the sake of just having something there, but I know it won't show what I want. Thanks!
var data = {
d: {
results: [
{ TypeOfIssueValue: '456' },
{ TypeOfIssueValue: '123' },
{ TypeOfIssueValue: '789' },
{ TypeOfIssueValue: '123' }
]
}
};
var filteredItems = data.d.results.filter(function(item){
return item.TypeOfIssueValue == '123';
});
var count = filteredItems.length;
document.getElementById("output").innerHTML = "Number of items with value '123': " + count;
<div id="output"/>
You could first map the TypeOfIssueValue values to a new array and then count each occurence based on this answer.
The code would be :
var a = data.d.results.map(function(issue) {
return issue.TypeOfIssueValue
});
result = {};
for (i = 0; i < a.length; ++i) {
if (!result[a[i]])
result[a[i]] = 0;
++result[a[i]];
}
The result will be an object with property being type of issue and value being the count of each.
Let me know if this makes sense.
Thanks #srinivas. I accepted your response, although I made some modifications, just in case they are useful to someone else.
I added a class to the span badge and added a new array to push the issues:
issuesArray.push(data.d.results[i].TypeOfIssueValue);
$('#myDataList').append('' + issue + '<span class="badge badgeSpan"></span>');
Then I addded a done() to run after the getJSON:
.done(
function(){ var resultado = foo(issuesArray)[1];
console.log(resultado);
var badges = $('.badgeSpan');
for (var j = 0; j < resultado.length; j++){
badges[j].innerHTML = resultado[j];
}
});
Last I made a small modificfation to the function foo() that you provided:
testArray = [];
function foo(arr) {
var a = [], b = [], prev;
for ( var i = 0; i < arr.length; i++ ) {
if ( arr[i] !== prev ) {
a.push(arr[i]);
b.push(1);
} else {
b[b.length-1]++;
}
prev = arr[i];
}
testArray.push(a,b)
return testArray;
}
This maybe a very unorthodox solution, but it worked for me. Thanks again.
I have a little piece of code that reads some ajax (this bit works) from a server.
var self = this;
var serverItems = new Array();
var playersOnlineElement = $("#playersOnline");
function DataPair(k, v) {
this.key = k;
console.log("new datapair: " + k + ", " + v);
this.value = v;
}
DataPair.prototype.getKey = function() {
return this.key;
}
DataPair.prototype.getValue = function() {
return this.value;
}
$.getJSON("http://127.0.0.1", function(data) {
$.each(data, function(key, val) {
var pair = new DataPair(key, val);
self.serverItems.push(pair);
});
});
console.log(serverItems.length); //Problem is here
for (var i = 0; i < serverItems.length; i = i + 1) {
var dpair = serverItems[i];
if (dpair.getKey() === "playersOnline") {
self.playersOnlineElement.text("Players Online: " + dpair.getValue());
}
}
The datapair and the JSON get loaded but when they are pushed to the array it doesn't seem to work. I tried with self.serverItems and just serverItems because netbeans showed me the scope of the variables being good if I used just serverItems but I am a bit confused as to why this doesn't work. Can anyone help me?
I put in comments where the error is. serverItems.length is 0 even though when debugging in a browser in the DOM tree it has an array serverItems with all the data inside.
Assumingly this serverItems is in another scope and not the one I am calling when I want to get the length?
add this code into the success part, since its asynchronous...
for (var i = 0; i < serverItems.length; i = i + 1) {
var dpair = serverItems[i];
if (dpair.getKey() === "playersOnline") {
self.playersOnlineElement.text("Players Online: " + dpair.getValue());
}
to...
$.getJSON("http://127.0.0.1", function(data) {
$.each(data, function(key, val) {
var pair = new DataPair(key, val);
self.serverItems.push(pair);
for (var i = 0; i < serverItems.length; i = i + 1) {
var dpair = serverItems[i];
if (dpair.getKey() === "playersOnline") {
self.playersOnlineElement.text("Players Online: " + dpair.getValue());
}
});
});
I am Bobi from Macedonia, and I stumbled upon one ugly problem with
my JavaScript/jQuery code.
I want to enter some values in my textarea, and then according to the specific formula
those values need to be calculated and the result need to be presented with alert.
Here is my code...
//First this is my formula
function calc(data) {
ret = [];
for(var i = 0; i < data.length; i++) {
ret[i] = (3.5 + data[i] + 0.5 * (data[i] - 3));
}
return ret;
}
//Now, taking values from the text area using valHooks
$.valHooks.textarea = {
get: function(elem) {
return elem.value.replace( /\r?\n/g, "\r\n" );
}
};
$('button').click(function() {
//in this step the values are successfully taken from the textarea
var sample = {};
sample.data = $('textarea').val();
//alert(sample.data); <-- this works fine
var result = {};
result.data = calc(sample.data); //but here seems to be the problem
alert(result.data); //the alert shows some gibberish values
So for example, if I enter these values 1.6, 3.9, 3.3, 4.0, 2.5, 2.8...
The alert need to show these calculated values: 4.4, 7.85, 6.95, 8.0, 5.75, 6.2...
Here is also jsfiddle
http://jsfiddle.net/Avramoski/skqG4/
I know that I am missing something small, but God knows what it is...
Please help! :(
do the following three changes as i noted.. and enjoy codding.. :)
function calc(data) {
ret = [];
for(var i = 0; i < data.length; i++) {
data[i] = parseFloat(data[i]); // here u want to parse ur string to float
ret[i] = (3.5 + data[i] + 0.5 * (data[i] - 3));
ret[i] = Math.round(ret[i] * 100) / 100; // this code for get rounded answer like exactly u needed
}
return ret;
}
$.valHooks.textarea = {
get: function(elem) {
return elem.value.replace( /\r?\n/g, "\r\n" );
}
};
$('button').click(function() {
var sample = {};
sample.data = $('textarea').val();
sample.data = sample.data.split(","); //textarea value transferring to array
//alert(sample.data);
var result = {};
result.data = calc(sample.data);
alert(result.data);
} // and dont miss this curly bracket :D
Click FIDDLE link to demo result.
You must check parseFloat number was valid.
$(function () {
function calc(data) {
ret = [];
var res=data.split(',');
for(var i = 0; i < res.length; i++) {
var parseNumber=parseFloat(res[i]);
ret[i] = (3.5 + parseNumber + 0.5 * (parseNumber - 3)).toFixed(2);
}
return ret;
}
//Taking values from the text area using valHooks
$.valHooks.textarea = {
get: function(elem) {
return elem.value.replace( /\r?\n/g, "\r\n" );
}
};
$('button').click(function() {
var result = {};
result.data = calc(sample.data);
alert(result.data);
});
});