How to retrieve the max value of a function output - javascript

I have a function f(x). I want to calculate x where f(x) = max. How can I do that in a script?
Given: x is a positive number, f(x) can be positive or negative.
I want to start with x = 1.
If f(1) is already negative I'm not interested anymore.
With increasing x, also f(x) returns increasing values, until a peak is reached, and then f(x) decreases. x at the peak is what I am interested in.
EDIT: Ok what I tried so far:
I tried starting with x = 1, then x *=2. If f(x) is smaller then the last result, I set back x to x/4.
Example: f(16) = 9, f(32) = 11, f(64) = 10. The peak can be between x=16 and x=64. So my new starting point is f(16). From there on, I want to continue in a similar way, but I cant find an algorithm.
Here is what I got so far:
let x = 1
let lasty = 0
let holder = 1
while (iteration++ < 20) {
let y = myFunction(x)
if(y < lasty ) {
x = x / 4
holder = 1
}
x += holder * 2
holder += 1
lasty = y
}
EDIT2: My improved version which works quite good but for sure not perfect:
let x = 1
let lasty = 0
let iteration = 0
let previousX = 1
let lastX = 1
let step = 2
let maxY = -Infinity
let bestX = 0
let randomInput = Math.random
while (iteration++ < 20) {
let y = myFunction(x, randomInput) //added randomInput to show the function does not rely on x alone
if (y < 0 && iteration == 1) break
if(y > maxY) {
maxY = y
bestX = x
}
if (y < lasty) {
x = previousX
step *= 0.8
lasty = 0
} else {
previousX = lastX
lastX = x
x = x * step
lasty = y
}
}
if(bestX > 0) {
console.log(`Got best x: ${bestX}`)
}
EDIT3: Added random additional parameter to emphasise the needed approach
EDIT4: I should also mention that the probability of f(x) = max is the highest when 0 < x < 100000

Assuming you want to maximise y, You can just store the x and y values where xy is highest:
let highestX = 1; // this is just the corresponding x value for the highest y
let highestY = -Infinity;
let x = 1
let lasty = 0
let holder = 1
while (iteration++ < 20) {
let y = myFunction(x);
// code for storing the highest y and corresponding x
if (y > highestY) {
highestY = y;
highestX = x;
}
if(y < lasty ) {
x = x / 4
holder = 1
}
x += holder * 2
holder += 1
lasty = y
}
console.log('f(x) is maximised when x =', highestX);

If you know the function has a single peak in a given range, and the closest value within a tolerance is acceptable, then a simple binary search should be all you need. Here we default the range to the entire safe integer range, but you can supply your own with findPeak (tolerance) (fn, rangeMin, rangeMax), perhaps something like findPeak (1e-8) (fn, 0, 100000).
const findPeak = (ε) => (
fn,
min = Number.MIN_SAFE_INTEGER,
max = Number.MAX_SAFE_INTEGER,
mid = min / 2 + max / 2
) =>
max - min < ε
? mid
: fn (min) < fn (max)
? findPeak (ε) (fn, mid, max)
: findPeak (ε) (fn, min, mid)
const fn = n => 600 + 50 * n - n ** 2
console .log (findPeak (1e-8) (fn)) //=> 24.99999991050572
This code is simple. It is less efficient than it might be if we took advantage of the fact that we will reuse fn (min) or fn (max) on each subsequent call, and probably would be faster with a while loop rather than the recursion. I'll leave such optimization to you. But I would first see if this is already fast enough, as simple code is much easier to work with.

It could be solved using recursive function calls.
// array of arguments
const args = [...Array(16).keys()];
// sample function
const sampleFunc = (x) => Math.sin(x);
// recursive function
function getElementWithFuncMaximum(arr, func, index = 0, currValue = 0) {
const currFuncValue = func(arr[index]);
return currFuncValue >= currValue
? getElementWithFuncMaximum(arr, func, index + 1, currFuncValue)
: arr[index - 1];
}
console.log(getElementWithFuncMaximum(args, sampleFunc));

Related

Check if value equals 0 regardless of decimal values?

I'm balancing the sigma of a Gaussian kernel. I desire to break the while loop once the first index of the array is equal to 0.(any decimal value).
I found that simply trying to match 0 won't match if the value also contains any decimals like 0.000013301.
var gaussianKernel1d = (function() {
var sqr2pi = Math.sqrt(2 * Math.PI);
return function gaussianKernel1d(size, sigma) {
'use strict';
// ensure size is even and prepare variables
var width = (size / 2) | 0,
kernel = new Array(width * 2 + 1),
norm = 1.0 / (sqr2pi * sigma),
coefficient = 2 * sigma * sigma,
total = 0,
x;
// set values and increment total
for (x = -width; x <= width; x++) {
total += kernel[width + x] = norm * Math.exp((-x * x) / coefficient);
}
// divide by total to make sure the sum of all the values is equal to 1
for (x = 0; x < kernel.length; x++) {
kernel[x] /= total;
}
return kernel;
};
})();
let i = 0.01;
let kernelArray = gaussianKernel1d(512, i);
while (kernelArray[0] === 0) {
i = i + 0.01;
kernelArray = gaussianKernel1d(512, i);
Same is also true when using Array[0] !== 0.0)
How can I match any values in the dataset that equal 0 regardless of the decimal values? And without converting the array to integers.
epascarello's solution is correct:
while (Math.floor(kernelArray[0]) === 0)
That will continue looping as long as kernelArray[0] is a value >= 0 and < 1.
Or of course, the other obvious approach is just to write the equation in the description above:
while (kernelArray[0]) >= 0 && kernelArray[0] < 1)
Try following
$b = 0;
while ( (string) Array[0] !== (string) $b) {
// code that just regenerates the random values
}

Solving for unknown exponent

I'trying to make a function creates a list of exponentially increasing numbers where the sum of the numbers is equal to some maximum.
For example:
/*
* What do I have to raise N by in order for the sum to be 40
*/
(1**x + 2**x + 3**x + 4**x + 5**x) === 40;
/*
* Wolframalpha tells me: x = 1.76445
* But how can I solve with JS.
*/
function listOfNumbers(n, maxSum) {
// implementation
}
var result = listOfNumbers(5, 40);
/*
* result === [1, 3.397..., 6.947..., 11.542..., 17.111...]
*
*/
result.reduce((acc, n) => acc += n) === 40
try https://en.wikipedia.org/wiki/Bisection_method
TOLERANCE = 1e-5;
let f = x => (1 ** x + 2 ** x + 3 ** x + 4 ** x + 5 ** x - 40);
let
min = 0,
max = 1,
x = 0;
// roughly locate the upper bound
while (f(max) < 0)
max *= 2;
// repeatedly bisect the interval [min, max]
while (1) {
x = (min + max) / 2;
let r = f(x);
if (Math.abs(r) < TOLERANCE)
break;
if (r > 0) {
max = x
} else {
min = x
}
}
// now, x is a "good enough" approximation of the root
console.log(x);

How can I make power method?

I want make the power method
I made this :
var x = 2, n = 3, i;
for (i = 1; i < n; i++) {
x = x * x;
}
console.log(x);
This gives 16 as result but expected is x^n = 8.
This function doesn't compute the power because it squares the intermediate results. You should use a separate variable like this:
var x= 2 ,n= 3, i;
var y = x;
for(i=1;i<n;i++){
x *= y;
}
console.log(x);
Try recursion:
const power = ( base, exponent ) => {
if( exponent === 0 ) return 1;
else return base * power( base, exponent - 1 );
};
Or try the normal for loop:
const power = ( base, exponent ) => {
let result = 1;
for( let i = 0; i < exponent; i++ )
result *= base;
return result;
};
The reason yours isn't working is because it tries to compute x = x^2 for n steps. Hence, the calculation is 2^2 = 4^2 = 16. The above code, instead, has a result variable which multiplies the base an exponent number of times.
You can use the built-in method Math.pow(number, power).
console.log(Math.pow(2, 10));

Convert a number into sum of two other numbers so the difference is minimum

In Mars, there are only two denominations of currency ,x and y. A
Marsian goes to a bar and the bill is "z". Using x and y he has to pay
the bill. But the bar doesn't tender change, any extra money will be
taken as tips.
So write a function in JavaScript that helps the marsian to reduce the
tips.
The function takes in x, y, z and returns the amount of tip he has to
pay.
Example 1
Input: 2, 5, 109
Output: 0
Explanation: 21 coins of 5, and 2 coins of 2
Example 2
Input: 5, 7, 43
Output: 0
Explanation: 4 coins of 7, and 3 coins of 5
Example 3
Input: 15, 19, 33
Output: 1
Explanation: 1 coin of 15 and 1 coin of 19
Solution: I think this is level one DP problem, something like subset sum. Like for finding the optimal tip for the larger number, knowing the optimal tip for all the below numbers would help.
const coinA = 2
const coinB = 5
const sum = 13
var arr = [];
arr[0] =0;
console.log(getMyTip(coinA, coinB, sum));
function getMyTip(){
for(var i=1; i<= sum; i++){
var minA, minB;
if( i < coinA){
minA = coinA - i;
}else{
minA = arr[i - coinA];
}
if( i < coinB){
minB = coinB - i;
}else{
minB = arr [i - coinB]
}
arr[i] = Math.min(minA, minB);
}
return arr[sum];
}
Jsfiddle: https://jsfiddle.net/7c4sbe46/
But I'm not sure why it is not getting accepted. Please let me know if I'm missing something with the logic here.
It is more related to diophantine equations, i.e. is there a solution to a.x+b.y=z ? The answer is yes if z is a multiple of the greatest common divisor of x and y (called it gcd). If not, your tip will be the difference between 1. the smaller number divisible by gcd and greater than z
and 2. z.
Once you know the value of the tip, you can even easily know the number of x and y that you need by slightly modifying the value of z to (z+tip).
#include <stdio.h>
int main()
{
int curr1, curr2, bill;
scanf("%d %d %d",&curr1,&curr2,&bill);
int gcd, tip=0;
int x=curr1;
int y=curr2;
while(x!=y)
{
if(x > y)
x -= y;
else
y -= x;
}
gcd=x;
if((bill%curr1==0) || (bill%curr2==0) || (bill%(curr1 + curr2)==0)){
tip = 0;
} else if(bill>(curr1 + curr2) && (bill % gcd==0)) {
tip = 0;
} else if((curr1 + curr2) > bill){
if(curr2 > curr1){
tip = (bill % (curr2-curr1));
}else{
tip = (bill % (curr1-curr2));
}
}
printf("%d",tip);
return 0;
}
There is no need to use dp for this. Here is the simple solution -
// x -> first currency denomination
// y -> second currency denomination
// z -> total bill
var calculateTip = function(x,y,z) {
var xMax = Math.floor(z/x);
var tip = y;
if(xMax == 0) {
tip = (x-z) < (Math.ceil(z/y)*y - z) ? (x-z) : (Math.ceil(z/y)*y - z);
}
while (xMax>=0) {
var tempTip = xMax*x + Math.ceil((z-xMax*x)/y)*y - z;
if(tempTip < tip) {
tip = tempTip;
}
xMax--;
}
return tip;
}
var minimumTip = function(x,y,z) {
if(x>y) {
return calculateTip(x,y,z);
} else {
return calculateTip(y,x,z);
}
}
console.log(minimumTip(2, 5, 109));
var findTip = function(x=2, y=5, z=13){
var x = x;
var y = y;
var z = z;
var tip ;
var temp1 = x;
var temp2 = y
function findNumber(num,total){
if(num > total){
return num-total;
}
else{
var q = Math.floor(total/num);
return ((q+1)*num)-total;
}
}
function findMin(a,b,c){
var min ;
if(a<b && a<c){
min = a
}else{
if(b<c){
min = b;
}else{
min = c;
}
}
return min;
}
while(temp1!=temp2)
{
if(temp1 > temp2)
temp1 -= temp2;
else
temp2 -= temp1;
}
var factor =temp1;
if(z%x == 0 || z%y == 0 || z%(x+y) == 0) {
tip = 0;
}else if(z%factor == 0 && z>=x*y - x -y){
tip = 0;
}
else {
var minX= findNumber(x,z);
var minY = findNumber(y,z);
var minXY = findNumber(x+y,z);
console.log(minX,minY,minXY)
tip = findMin(minX,minY,minXY);
}
alert('the tip is '+ tip.toString());
return tip;
}
findTip(21, 11, 109);

Javascript loop with dynamic start and end variables

This seems pretty basic, but I can't find the best method to do this... I'm trying to set up a function that loops between a user selected start and end variables. This is what I ended up with but I'm sure there is a better way to do it (demo).
Note: the x & y variables are indexed to one, not zero.
getWidths1 = function(x, y) {
var start = (x < y) ? x : y,
end = (x < y) ? y : x,
total = 0;
for (; start < end; start++) {
total += values[start - 1] || 0;
}
return total;
};
I tried this function, but the results are one result off when y > x:
getWidths2 = function(x, y) {
var total = 0,
diff = (x < y) ? 1 : -1;
while (x !== y) {
total += values[x - 1] || 0;
x += diff;
}
return w;
};
So, is the first function the best, or does someone have a better method?
The first isn't bad. I think this is slightly more traditional:
for (var i = start; i < end; i++){
}
Only real difference is that it doesn't affect start and end.
I'd make a few changes:
Use Math.min and Math.max - much more readable.
Don't subtract one from start if the first value you want is values[start].
var getWidths1 = function(x, y) {
var start = Math.min(x,y), end = Math.max(x,y);
var total = 0;
for (; start < end; start++) {
total += values[start] || 0;
}
return(total);
}
I agree with #kingjiv with the added caveat that if you want to include the item at y then you need:
for (var i = start; i <= end; i++){
...
}
As it is your code (both versions) will total the values from x inclusive to y exclusive.

Categories

Resources