This question already has answers here:
What is the (function() { } )() construct in JavaScript?
(28 answers)
Closed 8 years ago.
EDIT: Apolgies for the duplicate question but searching for " '()' Javascript " yielded no result for me.
Here goes ... I am doing some pixel manipulation on an image in PHP and porting some Javascript logic into PHP to achieve an effect that I have seen on a html5 canvas. The Javascript uses some curves calculation to achieve a "vintage effect". The pixel calculations get called within a loop:
Javascript:
for (var i = (width * height); i >= 0; --i) {
idx = i << 2;
// curves
if (!!_effect.curves) {
_imageData[idx ] = _effect.curves.r[ _imageData[idx ] ]; // r
_imageData[idx + 1] = _effect.curves.g[ _imageData[idx + 1] ]; // g
_imageData[idx + 2] = _effect.curves.b[ _imageData[idx + 2] ]; // b
}
}
The effect.curves object looks like:
var _effect = {
curves: (function() {
var rgb = function (x) {
return -12 * Math.sin( x * 2 * Math.PI / 255 ) + x;
},
r = function(x) {
return -0.2 * Math.pow(255 * x, 0.5) * Math.sin(Math.PI * (-0.0000195 * Math.pow(x, 2) + 0.0125 * x ) ) + x;
},
g = function(x) {
return -0.001045244139166791 * Math.pow(x,2) + 1.2665372554875318 * x;
},
b = function(x) {
return 0.57254902 * x + 53;
},
c = {r:[],g:[],b:[]};
for(var i=0;i<=255;++i) {
c.r[i] = r( rgb(i) );
c.g[i] = g( rgb(i) );
c.b[i] = b( rgb(i) );
}
return c;
})(), // <-- THIS PART
};
My question is: is the () at the line noted just above telling the curves function to run when it's called from within the _imageData loop?
No, the function call happens as part of the initialization of that object ("_effect"). The value of the property "curves" will be the return value from invoking that function. The function builds up an object and returns it.
In JavaScript, a reference to a function followed by a parenthesized argument list is always a function call.
To make it more clear, imagine that that function had be declared as an ordinary function:
function makeCurves() {
var rgb = function (x) {
return -12 * Math.sin( x * 2 * Math.PI / 255 ) + x;
},
r = function(x) {
return -0.2 * Math.pow(255 * x, 0.5) * Math.sin(Math.PI * (-0.0000195 * Math.pow(x, 2) + 0.0125 * x ) ) + x;
},
g = function(x) {
return -0.001045244139166791 * Math.pow(x,2) + 1.2665372554875318 * x;
},
b = function(x) {
return 0.57254902 * x + 53;
},
c = {r:[],g:[],b:[]};
for(var i=0;i<=255;++i) {
c.r[i] = r( rgb(i) );
c.g[i] = g( rgb(i) );
c.b[i] = b( rgb(i) );
}
return c;
}
Then the initialization would look like:
var _effect = {
curves: makeCurves()
};
It means the function is being called immediately after being created and being assigned to the curves variable.
Related
i am so newbie in programming. i had problem how to count the area and around of triangle.
i had code code some, but the output results are always wrong calculate.
function fungsiLuasSegitiga(a, b) {
var luas = (1 / 2) * a * b;
return luas;
}
function fungsiKllSegitiga(a, b) {
var c = Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2));
var kll = a + b + c;
return kll;
}
var x = prompt("masukkan nilai alas segitiga!");
var y = prompt("masukkan nilai tinggi segitiga!");
var d = fungsiLuasSegitiga(x, y);
var e = fungsiKllSegitiga(x, y);
alert("luas segitiga adalah " + d);
alert("keliling segitiga adalah " + e);
when i put number 3 and 4, the function fungsiLuasSegitiga count it be 345, but the result must be 12 (3+4+5).
prompt returns a string and not a number. So, kll calculation ends up being "3" + "4" + 5. This concatenates the string instead of summing the numbers. You need to parse it to a number before assigning it to x and y either by using unary plus operator or parseInt
function fungsiLuasSegitiga(a, b) {
var luas = (1 / 2) * a * b;
return luas;
}
function fungsiKllSegitiga(a, b) {
var c = Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2));
var kll = a + b + c;
return kll;
}
var x = +prompt("masukkan nilai alas segitiga!");
var y = +prompt("masukkan nilai tinggi segitiga!");
var d = fungsiLuasSegitiga(x, y);
var e = fungsiKllSegitiga(x, y);
alert("luas segitiga adalah " + d);
alert("keliling segitiga adalah " + e);
I have a for loop like this:
var speed = 100;
var curve = [];
for (var i = 0; i < 5; i++) {
curve.push(i*speed);
}
So for the last loop its 400, the question is how do i implement ease in and out in the for loop? roughly in the end the result should be like this? [0,52,200,348,400]
EDIT:
var defaultSpin = 24;
var totalSlices = 12;
for (var i = 0; i < defaultSpin; i++) {
highlight(divs[i%totalSlices], i*100, 100);
}
function highlight(el, delay, duration) {
setTimeout(function() {
el.className += ' active';
setTimeout(function() {
el.className = 'pie';
}, duration)
}, delay)
}
It is a spin wheel with highlight instead of actually spinning it. I'm calling the above function with the loop. for now it only has constant speed because each loop difference is only 100 so the 1st hightlight delay is 0 and it start immediately. 2nd is 100, 3rd is 200 and so on.
Lots of common easing functions are shown here:
http://gizma.com/easing/
Here is an example of how to use one:
// from http://gizma.com/easing/
var easeInOutQuad = function (t, b, c, d) {
t /= d/2;
if (t < 1) return c/2*t*t + b;
t--;
return -c/2 * (t*(t-2) - 1) + b;
};
var steps = 4
var speed = 100
var curve = []
for (var i = 0; i < steps+1; i++) {
var stepValue = easeInOutQuad(i, 0, speed*steps, steps);
curve.push(stepValue);
}
console.log(curve); // [0, 50, 200, 350, 400]
Hey take a note of this snippet
/*\
* Raphael.easing_formulas
[ property ]
**
* Object that contains easing formulas for animation. You could extend it with your own. By default it has following list of easing:
# <ul>
# <li>“linear”</li>
# <li>“<” or “easeIn” or “ease-in”</li>
# <li>“>” or “easeOut” or “ease-out”</li>
# <li>“<>” or “easeInOut” or “ease-in-out”</li>
# <li>“backIn” or “back-in”</li>
# <li>“backOut” or “back-out”</li>
# <li>“elastic”</li>
# <li>“bounce”</li>
# </ul>
# <p>See also Easing demo.</p>
\*/
var ef = R.easing_formulas = {
linear: function (n) {
return n;
},
"<": function (n) {
return pow(n, 1.7);
},
">": function (n) {
return pow(n, .48);
},
"<>": function (n) {
var q = .48 - n / 1.04,
Q = math.sqrt(.1734 + q * q),
x = Q - q,
X = pow(abs(x), 1 / 3) * (x < 0 ? -1 : 1),
y = -Q - q,
Y = pow(abs(y), 1 / 3) * (y < 0 ? -1 : 1),
t = X + Y + .5;
return (1 - t) * 3 * t * t + t * t * t;
},
backIn: function (n) {
var s = 1.70158;
return n * n * ((s + 1) * n - s);
},
backOut: function (n) {
n = n - 1;
var s = 1.70158;
return n * n * ((s + 1) * n + s) + 1;
},
elastic: function (n) {
if (n == !!n) {
return n;
}
return pow(2, -10 * n) * math.sin((n - .075) * (2 * PI) / .3) + 1;
},
bounce: function (n) {
var s = 7.5625,
p = 2.75,
l;
if (n < (1 / p)) {
l = s * n * n;
} else {
if (n < (2 / p)) {
n -= (1.5 / p);
l = s * n * n + .75;
} else {
if (n < (2.5 / p)) {
n -= (2.25 / p);
l = s * n * n + .9375;
} else {
n -= (2.625 / p);
l = s * n * n + .984375;
}
}
}
return l;
}
};
ef.easeIn = ef["ease-in"] = ef["<"];
ef.easeOut = ef["ease-out"] = ef[">"];
ef.easeInOut = ef["ease-in-out"] = ef["<>"];
ef["back-in"] = ef.backIn;
ef["back-out"] = ef.backOut;
This is a snippet from Raphael. Here you see you have a list of animation ease-in formulas.
Lets try one of them, e.g. ease-in
var pow = Math.pow;
function easeIn(n) {
return pow(n, 1.7);
}
function easeOut(n) {
return pow(n, .48);
}
function process(min, max, intervals, fN) {
var diff = 1 / intervals,
difference = max - min,
curve = [];
for (i = diff; i <= 1; i += diff) {
curve.push(min + (difference * fN(i)));
}
return curve;
}
console.log('easeIn: \n', process(0, 400, 5, easeIn));
console.log('easeOut: \n', process(0, 400, 5, easeOut));
This might not be in sync with the output you have expected. But these are the formulas a renowned JS SVG library like Rapahel uses. You would love this demo
I want to create a function that generates mathematical expressions like ( 21 + 13 ) * 56 using random numbers from 1 to 100.
The function must take a level parameter. The level determines the length of the generated equation, for example:
// level 2
75 - 54 = 21
62 + 15 = 77
88 / 22 = 4
93 + 22 = 115
90 * 11 = 990
// level 3
( 21 + 13 ) * 56 = 1904
82 - 19 + 16 = 79
51 * ( 68 - 2 ) = 3366
So far I can create equations without brackets but I need help that would give me a reliable solution. This is what I have done so far:
var level = 3;
var x = ['/', '*', '-', '+'];
function randomNumberRange(min, max) {
return Math.floor(Math.random() * (max - min) + min);
}
var a = '';
for (var i = 0; i < level; i++) {
if (i !== level - 1) {
var n1 = randomNumberRange(1, 100);
var m = randomNumberRange(0, x.length);
var str = x[m];
a += n1;
a += ' ' + str + ' ';
} else {
a += n1;
}
}
I picked up the idea of #plamut to create a binary tree, where each node represents an operator with a left and a right side.
For instance, the equation 2 * (3 + 4) can be seen as
*
/ \
2 +
/ \
3 4
You can represent this quite straight forward using objects as follows:
var TreeNode = function(left, right, operator) {
this.left = left;
this.right = right;
this.operator = operator;
this.toString = function() {
return '(' + left + ' ' + operator + ' ' + right + ')';
}
}
Then you can create a recursive function to build such trees, where one sub-tree would have half of the desired total number of nodes (= length of equation):
function buildTree(numNodes) {
if (numNodes === 1)
return randomNumberRange(1, 100);
var numLeft = Math.floor(numNodes / 2);
var leftSubTree = buildTree(numLeft);
var numRight = Math.ceil(numNodes / 2);
var rightSubTree = buildTree(numRight);
var m = randomNumberRange(0, x.length);
var str = x[m];
return new TreeNode(leftSubTree, rightSubTree, str);
}
Here's a JSFiddle with a working example.
Maybe you still want to care about special cases, like avoiding brackets at top level, but that shouldn't be too hard from here.
Here an implementation that works for +, -, *, /, %, ^, parentheses and functions (min, max, sin, cos, tan, log). You can also easily add support for more functions like sqrt, asin, acos...
const operatorsKeys = ['+', '-', '*', '/', '%', '^'];
const functions = {
min: { arity: 2 },
max: { arity: 2 },
sin: { arity: 1 },
cos: { arity: 1 },
tan: { arity: 1 },
log: { arity: 1 }
};
const functionsKeys = Object.keys(functions);
// ⚠️ High probability that the expression calculation is NaN because of 'log(-1)', '-1 ^ 0.1', '1 % 0', '1 / 0 * 0'
function getRandomMathExpression(nbNodes: number): string {
assert(nbNodes > 0, 'nbNodes must be > 0');
if (nbNodes === 1) {
//return getRandomInt(-9, 9).toString();
return getRandomFloat(-100, 100, { decimalPlaces: 2 }).toString();
}
const operator = operatorsKeys[getRandomInt(0, operatorsKeys.length - 1)];
const func = functionsKeys[getRandomInt(0, functionsKeys.length - 1)];
const nbNodesLeft = Math.floor(nbNodes / 2);
const nbNodesRight = Math.ceil(nbNodes / 2);
const left = getRandomMathExpression(nbNodesLeft);
const right = getRandomMathExpression(nbNodesRight);
let expr;
if (Math.random() < 0.5) {
// eval("-1 ** 2") => eval("(-1) ** 2")
// Fix "SyntaxError: Unary operator used immediately before exponentiation expression..."
expr = operator === '^' ? `(${left}) ${operator} ${right}` : `${left} ${operator} ${right}`;
expr = Math.random() < 0.5 ? `(${expr})` : expr;
} else {
expr =
functions[func]!.arity === 2
? `${func}(${left}, ${right})`
: `${func}(${left}) ${operator} ${right}`;
}
return expr;
}
// Exported for testing purposes only
// https://stackoverflow.com/a/45736131
export function getNumberWithDecimalPlaces(num: number, decimalPlaces: number) {
const power = 10 ** decimalPlaces;
return Math.floor(num * power) / power;
}
type GetRandomNumberOptions = {
/**
* The number of digits to appear after the decimal point.
* https://ell.stackexchange.com/q/141863
*/
decimalPlaces?: number;
};
// min included, max excluded
export function getRandomFloat(min: number, max: number, options: GetRandomNumberOptions = {}) {
const { decimalPlaces } = options;
const num = Math.random() * (max - min) + min;
if (decimalPlaces === undefined) {
return num;
}
return getNumberWithDecimalPlaces(num, decimalPlaces);
}
// min/max included
export function getRandomInt(min: number, max: number) {
// https://stackoverflow.com/a/7228322
return Math.floor(Math.random() * (max - min + 1)) + min;
}
Examples / unit tests:
function convertMathExpressionToEval(expr: string) {
let evalExpr = expr.replaceAll('^', '**');
functionsKeys.forEach(func => (evalExpr = evalExpr.replaceAll(func, `Math.${func}`)));
return evalExpr;
}
test('getRandomMathExpression()', () => {
const numberRegex = /-?\d+(\.\d+)?/g;
for (let i = 0; i < 100; i++) {
// 13.69
// -97.11
{
const expr = getRandomMathExpression(1);
expect(expr).toMatch(/^-?\d+(\.\d+)?$/);
expect(eval(convertMathExpressionToEval(expr))).toEqual(expect.any(Number));
}
// cos(-20.85) * 65.04
// max(50.44, 66.98)
// (-13.33 / 70.81)
// -51.48 / -83.07
{
const expr = getRandomMathExpression(2);
expect(expr.match(numberRegex)).toHaveLength(2);
expect(eval(convertMathExpressionToEval(expr))).toEqual(expect.any(Number));
}
// min(-91.65, min(99.88, -33.67))
// (-77.28 % sin(-52.18) + -20.19)
// (67.58 % -32.31 * -7.73)
// (28.33) ^ (-32.59) ^ -80.54
{
const expr = getRandomMathExpression(3);
expect(expr.match(numberRegex)).toHaveLength(3);
expect(eval(convertMathExpressionToEval(expr))).toEqual(expect.any(Number));
}
// cos(max(24.57, 84.07)) ^ tan(51.78) - -45.52
// (min(-40.91, -67.48) * sin(-25.99) ^ -29.35)
// cos(1.61 - -22.15) % (-70.39 * 0.98)
// ((30.91) ^ -63.24) + 76.72 / 61.07
{
const expr = getRandomMathExpression(4);
expect(expr.match(numberRegex)).toHaveLength(4);
expect(eval(convertMathExpressionToEval(expr))).toEqual(expect.any(Number));
}
// tan((24.97) ^ 55.61) ^ (-46.74 % -31.38 * 84.34)
// max(tan(-7.78) + -2.43, max(35.48, (6.13 % 25.54)))
// ((5.66 / 23.21) - (-22.93 % 96.56 * 52.12))
// (((-40.93 % 13.72)) ^ (29.48 * 57.34 + 13.26))
{
const expr = getRandomMathExpression(5);
expect(expr.match(numberRegex)).toHaveLength(5);
expect(eval(convertMathExpressionToEval(expr))).toEqual(expect.any(Number));
}
}
// Torture test, should not throw
for (let i = 0; i < 100; i++) {
const expr = getRandomMathExpression(1000);
expect(expr.match(numberRegex)).toHaveLength(1000);
// The longer the expression, the more likely it will result in a NaN
expect(eval(convertMathExpressionToEval(expr))).toEqual(expect.any(Number));
}
});
More here: https://gist.github.com/tkrotoff/b0b1d39da340f5fc6c5e2a79a8b6cec0
I've decided to try working through the MIT SICP course, but in Javascript.
The following code outputs undefined, but it should output a fairly accurate guess of the square root of 5.
I've tested all of the smaller functions and they all work as expected, the problem must be somewhere in the recursive guessRoot() function, but I can't seem to see the problem.
var square = function(x) {
return x * x;
};
var abs = function(x) {
return x > 0 ? x : -x;
};
var goodEnough = function(g, x) {
return abs(square(g) - x) < 0.01;
};
var average = function(x, y) {
return (x + y) / 2;
};
var improve = function(g, x) {
return average(g, (x / g));
};
var guessRoot = function(guess, x) {
if (goodEnough(guess, x)) {
return guess;
} else {
guessRoot(improve(guess, x), x);
}
};
console.log(guessRoot(2.5, 5));
Looks like you're just missing a return in the recursive step.
var guessRoot = function(guess, x) {
if (goodEnough(guess, x)) {
return guess;
} else {
return guessRoot(improve(guess, x), x); // ... here
}
};
http://jsfiddle.net/mattball/TyLsL
Okay....
I have a lot of uncontrolled numbers i want to round:
51255 -> 55000
25 -> 25
9214 -> 9500
13135 -> 15000
25123 -> 30000
I have tried modifying the numbers as string and counting length....
But is there a simple way using some Math function maybe?
Here's my late answer. Uses no Math methods.
function toN5( x ) {
var i = 5;
while( x >= 100 ) {x/=10; i*=10;}
return ((~~(x/5))+(x%5?1:0)) * i;
}
DEMO: http://jsbin.com/ujamoj/edit#javascript,live
[51255, 24, 25, 26, 9214, 13135, 25123, 1, 9, 0].map( toN5 );
// [55000, 25, 25, 30, 9500, 15000, 30000, 5, 10, 0]
Or this is perhaps a bit cleaner:
function toN5( x ) {
var i = 1;
while( x >= 100 ) {x/=10; i*=10;}
return (x + (5-((x%5)||5))) * i;
}
DEMO: http://jsbin.com/idowan/edit#javascript,live
To break it down:
function toN5( x ) {
// v---we're going to reduce x to the tens place, and for each place
// v reduction, we'll multiply i * 10 to restore x later.
var i = 1;
// as long as x >= 100, divide x by 10, and multiply i by 10.
while( x >= 100 ) {x/=10; i*=10;}
// Now round up to the next 5 by adding to x the difference between 5 and
// the remainder of x/5 (or if the remainder was 0, we substitute 5
// for the remainder, so it is (x + (5 - 5)), which of course equals x).
// So then since we are now in either the tens or ones place, and we've
// rounded to the next 5 (or stayed the same), we multiply by i to restore
// x to its original place.
return (x + (5-((x%5)||5))) * i;
}
Or to avoid logical operators, and just use arithmetic operators, we could do:
return (x + ((5-(x%5))%5)) * i;
And to spread it out a bit:
function toN5( x ) {
var i = 1;
while( x >= 100 ) {
x/=10;
i*=10;
}
var remainder = x % 5;
var distance_to_5 = (5 - remainder) % 5;
return (x + distance_to_5) * i;
}
var numbers = [51255, 25, 9214, 13135, 25123, 3, 6];
function weird_round(a) {
var len = a.toString().length;
var div = len == 1 ? 1 : Math.pow(10, len - 2);
return Math.ceil(a / 5 / div) * div * 5;
}
alert(numbers.map(weird_round));
Also updated for numbers below 10. Won't work properly for negative numbers either, just mention if you need this.
DEMO
I'm not sure why, but I thought it would be fun with regular expressions:
var result = +(number.toString().replace(/([1-9])([0-9])(.+)/, function() {
return Math.ceil(+(arguments[1] + '.' + arguments[2])) * 10 - (+arguments[2] < 5?5:0) + arguments[3].replace(/./g, '0');
}));
Working Demo
with(Math) {
var exp = floor(log(number)/log(10)) - 1;
exp = max(exp,0);
var n = number/pow(10,exp);
var n2 = ceil(n/5) * 5;
var result = n2 * pow(10,exp);
}
http://jsfiddle.net/NvvGf/4/
Caveat: only works for the natural numbers.
function round(number) {
var numberStr = number + "",
max,
i;
if (numberStr[1] > '4') {
numberStr[0] = parseInt(numberStr[0]) + 1;
numberStr[1] = '0';
} else {
numberStr[1] = '5';
}
for (i = 2; max = numberStr.length; i < max; i += 1) {
numberStr += '0';
}
return parseInt(numberStr);
}
Strange coincidence, I wrote something really similar not so long ago!
function iSuckAtNames(n) {
var n = n.toString(), len = n.length, res;
//Check the second number. if it's less than a 5, round down,
//If it's more/equal, round up
//Either way, we'll need to use this:
var res = parseFloat(n[0]) * Math.pow(10, len - 1); //e.g. 5 * 10^4 = 50000
if (n[1] <= 5) {
//we need to add a 5 right before the end!
res += 5 * Math.pow(10, len - 2);
}
else {
//We need another number of that size
res += Math.pow(10, len - 1);
}
return res;
}