3

I am using the following code to determine the Greatest Common Denominator (GCD) of two or three numbers:

Math.GCD = function(numbers) {
  for (var i = 1 ; i < numbers.length ; i++){
    if (numbers[i] || numbers[i] === 0)
      numbers[0] = twogcd(numbers[0], numbers[i]);
  }
  return numbers[0];

  function twogcd(first, second) {
    if (first < 0) first = -first;
    if (second < 0) second = -second;
    if (second > first) {var temp = first; first = second; second = temp;}
    while (true) {
        first %= second;
        if (first == 0) return second;
        second %= first;
        if (second == 0) return first;
    }
   }
};

Math.LCM = function(first,second) {
    return first * (second / this.GCD(first, second)); // CANNOT FIGURE OUT HOW TO EXTEND THIS TO THREE #s
};

// example
console.log(Math.GCD([4, 5, 10]));
Demo also in JSFiddle

Notice the function in there about the Least Common Multiple (LCM)

I am trying to extend this function so that it can compute the LCM of the same two or three user supplied inputs, but I cannot for the life of me get it right. I am a novice at JavaScript and would appreciate any help whatsoever. Note that if a field is left blank it should be omitted from the calculation also, as is done for the GCD.

KyleMit
  • 30,350
  • 66
  • 462
  • 664
newbie2015
  • 251
  • 3
  • 17

3 Answers3

7

You can use these functions:

function gcd2(a, b) {
  // Greatest common divisor of 2 integers
  if(!b) return b===0 ? a : NaN;
  return gcd2(b, a%b);
}
function gcd(array) {
  // Greatest common divisor of a list of integers
  var n = 0;
  for(var i=0; i<array.length; ++i)
    n = gcd2(array[i], n);
  return n;
}
function lcm2(a, b) {
  // Least common multiple of 2 integers
  return a*b / gcd2(a, b);
}
function lcm(array) {
  // Least common multiple of a list of integers
  var n = 1;
  for(var i=0; i<array.length; ++i)
    n = lcm2(array[i], n);
  return n;
}
Oriol
  • 274,082
  • 63
  • 437
  • 513
  • Tried this out and the `lcm2` function seems to return the second input value as opposed to the actual LCM. – newbie2015 Jan 22 '16 at 22:25
  • @newbie2015 It works for me, e.g. `lcm2(6,15) === 30`, not `15`. – Oriol Jan 22 '16 at 23:27
  • I made this fiddle, changing a few variables to correspond to what I had: https://jsfiddle.net/tjj7won4/85/ - perhaps I've implemented something incorrectly. – newbie2015 Jan 22 '16 at 23:56
  • 1
    Try https://jsfiddle.net/tjj7won4/100/. Or https://jsfiddle.net/tjj7won4/101/, if you want to ignore empty fields. – Oriol Jan 23 '16 at 00:15
  • You're using `var` statements everywhere, have inadequate spacing, using unbraced `for`s, and using inline `?` in a way that hurts readability. – Corman May 27 '21 at 02:27
2

Maybe you change the structure a little bit for GCDand LCM, so that both methods have only two arguments.

To get the result of more than two arguments, use Array.prototype.reduce(), which takes two elements from the array and returns a result, which is used as a new insert until the array is finished.

And while the LCM and the GCD are associative, you can chain it as desired.

Math.GCD = function twogcd(first, second) {
    if (first < 0) first = -first;
    if (second < 0) second = -second;
    if (second > first) { var temp = first; first = second; second = temp; }
    while (true) {
        first %= second;
        if (first == 0) return second;
        second %= first;
        if (second == 0) return first;
    }
};

Math.LCM = function (first, second) {
    return first * (second / Math.GCD(first, second));
};

document.getElementById('calc').addEventListener('click', function (e) {
    var first = +document.getElementById("first").value,
        second = +document.getElementById("second").value,
        third = +document.getElementById("third").value,
        numbers = [first, second, third],
        resultGCD = numbers.reduce(Math.GCD), // just chain it together
        resultLCM = numbers.reduce(Math.LCM); // just chain it together

    document.getElementById('gcd').innerHTML = resultGCD;
    document.getElementById('lcm').innerHTML = resultLCM;
});
GCD: <span id="gcd"></span><br />
LCM: <span id="lcm"></span><br />
<form name="sci-calc" method="POST" id="sci-calc">
    <input type="text" name="stuff[]" class="input-field" id="first" /><br />
    <input type="text" name="stuff[]" class="input-field" id="second" /><br />
    <input type="text" name="stuff[]" class="input-field" id="third" /><br />
    <button type="button" id="calc">CALC</button>
</form>
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
1

I haven't figured out what your code is doing but here is the function to find LCM:

LCM = function(numbers) {
  console.log(numbers)  
  if (numbers.length < 2) return
  first = numbers[0]
  second = numbers[1]
  var i = j = 1
  var mult1 = first * i++
  var mult2 = second * j++
  while (mult1 != mult2) {
    if (mult1 < mult2)
        mult1 = first * i++
    else
        mult2 = second * j++
  }
  if (numbers.length > 2) {
    numbers[1] = mult1 //I hope you're fine with the fact that 'numbers' gets modified
    mult1 = LCM(numbers.splice(1, numbers.length-1))
  }
    return mult1
}

I know It's not efficcient but it illustrates the idea of how to use it with any number of parameters (it's just called recursively).

The fiddle: https://jsfiddle.net/grabantot/fr0gzogL/

grabantot
  • 2,111
  • 20
  • 31
  • I really like this solution, but I'd prefer to stick with the three input fields, so I doctored your fiddle [https://jsfiddle.net/fr0gzogL/17/] but I couldn't get it to accept just two arguments. Is it possible? – newbie2015 Jan 22 '16 at 22:45