diff --git a/docs/utility-methods.md b/docs/utility-methods.md index 6625f7fa..b8d74787 100644 --- a/docs/utility-methods.md +++ b/docs/utility-methods.md @@ -79,6 +79,18 @@ Util.divide([1, 2, 3, 4], [1, 2, 3]); Util.div([1, [2, 3]], [10, [20, 30, 40]]); //=> [ 0.1, [ 0.1, 0.1, 0.05 ] ] + +// Raise one array to the power of another +Util.pow([1, 2, 3, 4], [2, 3, 4]); +//=> [ 1, 8, 81, 16 ] + +Util.pow([1, [2, 3]], [10, [2, 3, 4]]); +//=> [ 1, [ 4, 27, 16 ] ] + +// Return the squareroot of an array +Util.sqrt([2, [9, [16, 25], 144]]); +//=> [ 1.4142135623730951, [ 3, [ 4, 5 ], 12 ] ] + ``` ## sum @@ -136,8 +148,9 @@ The highest value will be 1, the lowest value will be 0. Util.normalize([0, 1, 2, 3, 4]); //=> [ 0, 0.25, 0.5, 0.75, 1 ] -Util.normalize([5, 12, 4, 17, 3]); -//=> [ 0.14285714285714285, 0.6428571428571429, 0.07142857142857142, 1, 0 ] +// works with n-dimensional arrays +Util.normalize([5, [12, [4, 17]], 3, 1]); +//=> [ 0.25, [ 0.6875, [ 0.1875, 1 ] ], 0.125, 0 ] ``` ## flatten diff --git a/src/utility.js b/src/utility.js index bed3d268..cbd2b536 100644 --- a/src/utility.js +++ b/src/utility.js @@ -102,6 +102,7 @@ function map(a, ...params){ } exports.map = map; exports.scale = map; +exports.remap = map; function _map(a, inLo=0, inHi=1, outLo=0, outHi=1, exp=1){ a = (a - inLo) / (inHi - inLo); @@ -142,22 +143,7 @@ exports.lerp = _mix; // @return {Number/Array} // function add(a=0, v=0){ - // if righthand side is array - if (Array.isArray(v)){ - a = (Array.isArray(a))? a : [a]; - let l1 = a.length, l2 = v.length, r = []; - let l = Math.max(l1, l2); - for (let i=0; i add(x, v)); + return arrayEval(a, v, (a, b) => { return a + b }); } exports.add = add; @@ -170,19 +156,7 @@ exports.add = add; // @return {Number/Array} // function subtract(a=0, v=0){ - if (Array.isArray(v)){ - a = (Array.isArray(a))? a : [a]; - let l1 = a.length, l2 = v.length, r = []; - let l = Math.max(l1, l2); - for (let i=0; i subtract(x, v)); + return arrayEval(a, v, (a, b) => { return a - b }); } exports.subtract = subtract; exports.sub = subtract; @@ -196,19 +170,7 @@ exports.sub = subtract; // @return {Number/Array} // function multiply(a=0, v=1){ - if (Array.isArray(v)){ - a = (Array.isArray(a))? a : [a]; - let l1 = a.length, l2 = v.length, r = []; - let l = Math.max(l1, l2); - for (let i=0; i multiply(x, v)); + return arrayEval(a, v, (a, b) => { return a * b }); } exports.multiply = multiply; exports.mul = multiply; @@ -222,22 +184,66 @@ exports.mul = multiply; // @return {Number/Array} // function divide(a=0, v=1){ + return arrayEval(a, v, (a, b) => { return a / b }); +} +exports.divide = divide; +exports.div = divide; + +// Return the remainder after division +// also works in the negative direction, so wrap starts at 0 +// +// @param {Int/Array} -> input value +// @param {Int/Array} -> divisor (optional, default=12) +// @return {Int/Array} -> remainder after division +// +function mod(a=0, v=12){ + return arrayEval(a, v, (a, b) => { return ((a % b) + b) % b }); +} +exports.mod = mod; + +// Raise a value of one array to the power of the value +// from the right hand array +// +// @param {Number/Array} -> base +// @param {Number/Array} -> exponent +// @return {Number/Array} -> result from function +// +function pow(a=0, v=1){ + return arrayEval(a, v, (a, b) => { return Math.pow(a, b) }); +} +exports.pow = pow; + +function sqrt(a=0){ + return arrayEval(a, 0, (a) => { return Math.sqrt(a) }); +} +exports.sqrt = sqrt; + +// Evaluate a function for a multi-dimensional array +// +// @params {Array|Number} -> left hand input array +// @params {Array|Number} -> right hand input array +// @params {Function} -> function to evaluate +// @return {Array|Number} -> result of evaluation +// +function arrayEval(a, v, func){ + // if righthand side is array if (Array.isArray(v)){ a = (Array.isArray(a))? a : [a]; let l1 = a.length, l2 = v.length, r = []; let l = Math.max(l1, l2); for (let i=0; i divide(x, v)); + // if lefthand side is array + return a.map(x => arrayEval(x, v, func)); } -exports.divide = divide; -exports.div = divide; // flatten a multidimensional array. Optionally set the depth // for the flattening @@ -253,31 +259,6 @@ function flatten(a=[0], depth=Infinity){ exports.flatten = flatten; exports.flat = flatten; -// Return the remainder after division -// also works in the negative direction, so wrap starts at 0 -// -// @param {Int/Array} -> input value -// @param {Int/Array} -> divisor (optional, default=12) -// @return {Int/Array} -> remainder after division -// -function mod(a, m=12){ - if (Array.isArray(m)){ - a = (Array.isArray(a))? a : [a]; - let l1 = a.length, l2 = m.length, r = []; - let l = Math.max(l1, l2); - for (let i=0; i mod(x, m)); -} -exports.mod = mod; - // Truncate all the values in an array towards 0, // sometimes referred to as rounding down // @@ -338,14 +319,13 @@ exports.min = minimum; // @param {Number/Array} -> input values // @return {Int/Array} -> normailzed values function normalize(a=[0]){ - a = (!Array.isArray(a))? [a] : a; // get minimum and maximum let min = minimum(a); let range = maximum(a) - min; // if range 0 then range = min and min = 0 if (!range) { range = min, min = 0; } // normalize and return - return a.map(x => (x - min) / range); + return divide(subtract(a, min), range); } exports.normalize = normalize; diff --git a/test/serialism.test.js b/test/serialism.test.js index 7b6cae74..1308a6ae 100644 --- a/test/serialism.test.js +++ b/test/serialism.test.js @@ -596,10 +596,6 @@ function testUtil(){ // test("Util.fold(Gen.spreadFloat(20, -4, 6), -2, 3)"); // test("Util.fold(Gen.sineFloat(20, 1, -5, 29), 0, 24)"); - test("Util.map(0.5, 0, 1, 0, 2)"); - test("Util.map(0.5, 0, 1, 0, 2, 0.5)"); - test("Util.map([0, 1, 2, 3, 4], 0, 4, -1, 1)"); - test("Util.add()"); test("Util.add(5, 2)"); test("Util.add([0, 3, 7], 2)"); @@ -635,6 +631,20 @@ function testUtil(){ test("Util.div([1, 2, 3], [10, 20, 30, 40])"); test("Util.div([1, [2, 3]], [10, [20, 30, 40]])"); test("Util.div([1, [2, 3], 4], [10, 20, 30])"); + + test("Util.pow()"); + test("Util.pow(5, 2)"); + test("Util.pow([2, 3, 4, 6], 2)"); + test("Util.pow(2, [2, 3, 4, 6])"); + test("Util.pow([1, 2, 3, 4], [2, 3, 4])"); + test("Util.pow([1, 2, 3], [2, 3, 4, 5])"); + test("Util.pow([1, [2, 3]], [10, [2, 3, 4]])"); + test("Util.pow([1, [2, 3], 4], [10, 2, 3])"); + + test("Util.sqrt()"); + test("Util.sqrt(9)"); + test("Util.sqrt([2, 9, 16, 27])"); + test("Util.sqrt([2, [9, [16, 25], 144]])"); test("Util.mod()"); test("Util.mod(7, 3)"); @@ -642,19 +652,27 @@ function testUtil(){ test("Util.mod(2, [0, 3, 7])"); test("Util.mod([-2, 4, 3, 7], 5)"); test("Util.mod([-2, [4, [3, 7]]], 5)"); - - test("Util.normalize(5)"); - test("Util.normalize([0, 3, 7])"); - test("Util.normalize([1, 2, 3, 4])"); - test("Util.normalize([5, 12, 4, 17, 3])"); - + test("Util.sum([1, 2, 3, 4])"); test("Util.sum([10, 'foo', 11, 'bar', 22])"); - + test("Util.trunc()"); test("Util.trunc([3.14, 5.12, 6.18])"); test("Util.trunc([[3.14, 5.12], 6.18])"); test("Util.trunc([[3.14, [5.12]], 6.18])"); + + test("Util.normalize()"); + test("Util.normalize(5)"); + test("Util.normalize([0, 3, 9, 12, 24])"); + test("Util.normalize(Gen.spread(5, -10, 6))"); + test("Util.normalize(Gen.spread(5, 50, 100))"); + test("Util.normalize([5, [12, [4, 17]], 3, 1])"); + + test("Util.map(0.5, 0, 1, 0, 2)"); + test("Util.map(Gen.spread(5), 0, 5, 0, 1)"); + Util.plot(Util.map(Gen.spreadF(30), 0, 1, 0, 1, 2), { height: 10 }); + + test("Util.map([0, 1, 2, 3, 4], 0, 4, -1, 1)"); let drawing = []; Rand.seed(628);