2

I am having a problem trying to solve an equation in programming.

Imagine I have this line of code:

Math.round(((x / 5) + Math.pow(x / 25, 1.3)) / 10) * 10;

Given x = 1000, the result is 320.

Now, how can I solve this equation given a result?

Imagine given the result 320 I want to get the minimum integer value of x that resolves that line of code.

/*320 =*/ Math.round(((x / 5) + Math.pow(x / 25, 1.3)) / 10) * 10;

I am having some hard time because of the Math.Round. Even thought that expression is a linear equation, the Math.Round makes way more solutions than one for x, so I want the minimum integer value for my solution.

Note that x is a integer and if I set x = 999 the result is still 320.

If I keep lowering x I can see that 984 (atleast in Chrome 64.0.3282.186) is the correct answer in this case, because is the lowest value of x equals to 320 in that expression/programming line.

Exprove
  • 1,301
  • 2
  • 18
  • 32
  • Parentheses are unbalanced in both of those code snippets. – CertainPerformance Mar 20 '18 at 02:16
  • 1
    You know the fact that sometimes it's really hard to figure out the inputs of some equations based on a given output is the very basis of cryptography – Paul Mar 20 '18 at 02:18
  • but `984` is lower than `990` so, how can 990 be the correct answer? – Jaromanda X Mar 20 '18 at 02:28
  • @JaromandaX I tested this function in C#, completely forgot that different compilers could have different behaviors like interpreting floating points. Can someone tell me if different browsers or computers might have different behaviors like this one? – Exprove Mar 20 '18 at 02:34
  • 1
    "*Even though that expression is a linear equation…*" sure, so you can apply regression to solve it. Once you've worked out the mathematic algorithm, then attempt a solution. Post again if you have trouble with that, not the maths. – RobG Mar 20 '18 at 02:35
  • What have you tried? I see a solicitation to solve the problem and not any code. Have you attempted a solution? – vol7ron Mar 20 '18 at 02:49

4 Answers4

2

Solving the equation with the Math.round just introduces boundary conditions.

If:

Math.round(((x / 5) + Math.pow(x / 25, 1.3)) / 10) * 10 = 320

Then:

Math.round(((x / 5) + Math.pow(x / 25, 1.3)) / 10)  = 32

By dividing both sides by 10. Now you have:

Math.round(expression) = 32

Which can be expressed as an inequality statement:

31.5 < expression < 32.4999..

The expression being equal to 31.5 represents one boundary, and the expression being equal to 32.499.. represents the other boundary.So solving for the boundaries would require solving for:

expression = 31.5 and expression = 32.49999...
((x / 5) + Math.pow(x / 25, 1.3))/10 = 31.5  and 
((x / 5) + Math.pow(x / 25, 1.3))/10 = 32.4999

Solving these two for x will give you the range of valid values for x. Now that's just algebra which I'm not going to do :)

webnetweaver
  • 192
  • 8
  • Would this work if the result was 32 instead 320? If you divide 32 by 10: `3.2 = Math.round(expression)`. Isn't that impossible since Math.round always round to a integer? – Exprove Mar 20 '18 at 15:26
  • Yea that's impossible. Math.round(x) can never equal 3.2 so there would be no solution for x. – webnetweaver Mar 20 '18 at 16:43
  • Exprove if you think I answered your question please mark it as correct so I can get some yummy stack overflow points for it :) – webnetweaver Mar 21 '18 at 14:13
1

I guess the most reliable way that works (albeit somewhat naive) is to loop through all valid numbers and check the predicate.

function getMinimumIntegerSolution(func, expectedResult){
  for(let i = 0 /*Or Number.MIN_SAFE_INTEGER for -ves*/; i< Number.MAX_SAFE_INTEGER ; i++ ) { 
    if(func(i) === expectedResult)
        return i;
  }
}

Now

getMinimumIntegerSolution((x) => Math.round(((x / 5) + Math.pow(x / 25, 1.3)) / 10) * 10 , 320)

This returns what you expect, 984

gawicks
  • 1,894
  • 15
  • 22
  • I have done this approach before posting this question, but for being honest it seems somewhat a "lazy" method. However is a solution and it is an easy one to understand. Thank you. – Exprove Mar 20 '18 at 14:14
0

Because the function defined by

f(n) = Math.round(((x / 5) + Math.pow(x / 25, 1.3)) / 10) * 10

is monotonous (in this case, increasing), you can do a binary search. Note that I wrote the following code originally in Java, and it is syntactically incorrect in Javascript, but should hopefully be straightforward to translate into the latter.

var x0 = 0;
var x1 = 1e6;
var Y = 320d;
var epsilon = 10d;

var x = (x1 - x0) / 2d;
var y = 0;

while (Math.abs(Y - (y = f(x))) > epsilon) {
   if (y > Y) {
      x = (x - x0) / 2d;
   } else {
      x = (x1 - x) / 2d;
   }
   // System.out.println(y + " " + x);
}

while (f(x) < Y)
   ++x;

// System.out.println(Math.round(x) + " " + f(x));

Running it on my computer leaving the System.out.println uncommented:

490250.0 250000.0
208490.0 125000.0
89370.0 62500.0
38640.0 31250.0
16870.0 15625.0
7440.0 7812.5
3310.0 3906.25
1490.0 1953.125
680.0 976.5625
984 320.0
  • Note that the last loop incrementing x is guaranteed to complete in less than epsilon steps.
  • The values of x0, x1 and epsilon can be tweaked to provide better bounds for your problem.
  • This algorithm will fail if the value of epsilon is "too small", because of the rounding happening in f.
  • The complexity of this solution is O(log2(x1 - x0)).
Alexandre Dupriez
  • 3,026
  • 20
  • 25
0

In addition to @webnetweaver answer. If you rearrange the final equation you get a high-order polynomial (13th degree) which is difficult to solve algebraically. You can use numerical methods as Newton's method. For numerical methods in JavaScript you can use numeric.js. You also need to solve only for the lower bound (31.5) in order to find the lowest integer x because the function is monotonic increasing. See also this post on numerical equation solving in JavaScript.

Here is a solution using Newton's method. It uses 0 as initial guess. It only takes five iterations for getting the minimum integer solution.

var result = 320;
var d = result - 5;

function func(x) {
  return x / 5 + 0.0152292 * Math.pow(x, 1.3) - d;
}

function deriv(x) {
  return 0.2 + 0.019798 * Math.pow(x, 0.3);
}

var epsilon = 0.001; //termination condition

function newton(guess) {
  var approx = guess - func(guess) / deriv(guess);
  if (Math.abs(guess - approx) > epsilon) {
    console.log("Guess: " + guess);
    return newton(approx);
  } else {
    //round solution up for minimum integer
    return Math.ceil(approx);
  }
}

console.log("Minimum integer: " + newton(0));