1

It's well known that any positive number can be expressed through at most 3 Triangular numbers. ( https://oeis.org/A000217 )

Example:

11 := 10 + 1

12 := 10 + 1 + 1

13 := 10 + 3

14 := 10 + 3 + 1

15 := 15

I am searching the representation of the positive number n through at most 3 possible Triangular summands. There can exist more than one representation of n. I am interested in the one with the greatest summands.

Is there a more effective way than 2 decreasing for and 1 increasing for loops to find the summands?

public void printMaxTriangularNumbers(int n){
  int[] tri = createTriangularNumbers(1000);

  lbl: for(int i = tri.length-1; ; i--){
    int tmp = n - tri[i];
    if(tmp == 0){
      System.out.println(tri[i]);
      break;
    }
    for(int j=i; j>0; j--){
      int tmp2 = tmp - tri[j];
      if(tmp2 ==0){
        System.out.println(tri[i]);
        System.out.println(tri[j]);
        break lbl;
      }
      for(int k=1; k <= j;k++){
        if(tmp2 - tri[k] == 0){
          System.out.println(tri[i]);
          System.out.println(tri[j]);
          System.out.println(tri[k]);
          break lbl;
        }
      }
    }
  }
}

public int[] createTriangularNumbers(int n){
  int[] out = new int[n+1];
  for(int i=1,sum=0; i<=n;i++){
    out[i] = sum += i;
  }
  return out;
}
TTho Einthausend
  • 609
  • 4
  • 13
  • 1
    Please explain what a triangular number is and show an [MRE] of your code for the solution you describe. Showing is better than describing, especially when it comes to code. – Yunnosch Aug 20 '20 at 18:25
  • 1
    14 is not a triangular number. – trincot Aug 20 '20 at 18:28
  • You are correct! Updated the question. – TTho Einthausend Aug 20 '20 at 18:36
  • The third loop is not necessary. Given 2 triangular numbers `t1, t2`, testing for "triangularity" of `n - t1 - t2` is next to trivial. – user58697 Aug 20 '20 at 18:50
  • 1
    I think your question fits more the domain of mathematics and better to be asked on a Math Stack Exchange [site](https://math.stackexchange.com/). – Giorgi Tsiklauri Aug 20 '20 at 19:00
  • How about 2 nested binary search? Just a thought. – nice_dev Aug 20 '20 at 19:26
  • Yes would work for trivial case, but in practice i calculate the ith Triangular number on the fly back and forth. Also i dont unterstand how to search the missing number? – TTho Einthausend Aug 20 '20 at 19:36
  • 1
    I gather that a triangular number is an integer `k` such that there exists an integer `j` with `k = j (j + 1) /2`. Given that, you need to solve `2 n = j1 (j1 + 1) + j2 (j2 + 1) + j3 (j3 + 1)` for some integers `j1`, `j2`, `j3`. This is a quadratic Diophantine equation in three variables. Maybe a web search for those terms will turn up some resources. Also, I second the recommendation for math.stackexchange.com. – Robert Dodier Aug 20 '20 at 19:41

2 Answers2

2

As far as I can see, there is no direct formula. An algorithm is needed. For instance, a greedy method does not work. Take for example the value 90:

  • The greatest triangular number not greater than 90 is 78. Remains 12
  • The greatest triangular number not greater than 12 is 10. Remains 2
  • And now it becomes clear we will need 4 terms which is not acceptable.

So I would propose a recursive/backtracking algorithm, where each recursive call deals with one summand only. Each level in the recursion takes first the highest possible triangular number, but if the recursive call fails, it will go for the second largest and dive into recursion again, until there is an acceptable sum.

We can use the formula mentioned at maths.stackexchange.com:

Let Tm be the largest triangular number less than or equal to c. You can actually get an explicit formula for m, namely: enter image description here

Here is a snippet that implements the recursion. When running it, you can introduce a value, and the triangular summands will be produced for it.

function getTriangularTerms(n, maxTerms) {
    if (maxTerms === 0 && n > 0) return null; // failure: too many terms
    if (n == 0) return []; // Ok! Return empty array to which terms can be prepended
    // Allow several attempts, each time with a
    //   lesser triangular summand:
    for (let k = Math.floor((Math.sqrt(1+8*n) - 1) / 2); k >= 1; k--) {
        let term = k * (k+1)/2;
        // Use recursion
        let result = getTriangularTerms(n - term, maxTerms - 1);
        // If result is not null, we have a match
        if (result) return [term, ...result]; // prepend term
    }
}

// I/O handling
let input = document.querySelector("input");
let output = document.querySelector("span");

(input.oninput = function () { // event handler for any change in the input
    let n = input.value;
    let terms = getTriangularTerms(n, 3); // allow 3 terms max.
    output.textContent = terms.join("+");
})(); // execute also at page load.
Enter number: <input type="number" value="14"><br>
Terms: <span></span>
trincot
  • 317,000
  • 35
  • 244
  • 286
  • @TThoEinthausend, it was only "wrong" by one unit (the author uses a different numbering of triangular numbers). To avoid confusion about this, I have now referenced a different post on maths.stackexchange, so it corresponds to the usual numbering of triangular numbers. – trincot Aug 21 '20 at 06:37
0

Since a triangular number is any number t that satisfies t=x(x+1)/2 for any natural number x, what you're asking is to solve

n = a(a+1)/2 + b(b+1)/2 + c(c+1)/2

and to find the solution (a,b,c) with greatest possible max(a,b,c). You didn't specify that you only allow solutions with 3 triangular numbers, so I will assume you also allow solutions of the form (a,b,c,d) and look for the one with the greatest max(a,b,c,d).

There might be multiple solutions, but one with at most 3 triangular numbers always exists. Since it's possible to form any number with 3 triangular numbers, you can find the largest triangular number t with t<=n, and then it will follow n=t+d, where d=n-t. d is a natural number >=0 and therefore can be composed by 3 triangular numbers itself. Since you're interested in the largest summand, the largest will be t, which can be computed with t=x(x+1)/2 where x=floor((sqrt(1+8n)-1)/2) (obtained by solving the formula n=x(x+1)/2+d).

As a practical example, take n=218. With the formula, we get x=20 and t=210, which indeed is the largest triangular number before 218. The other triangular numbers, in this case, will be 6, 1, 1 since the only way to compute 8 is with those.

SimoGecko
  • 88
  • 6
  • But best result with at most 3 summands is 190 + 28. – MBo Aug 20 '20 at 19:15
  • ... and you end up decomposing `218` into _four_ triangular numbers. Not exactly what the question is about. – user58697 Aug 20 '20 at 19:16
  • when the question was first asked it wasn't specified that only solutions with at most 3 triangular numbers were allowed, hence my assumption. since the poster added more detail to the question this makes this solution unfit – SimoGecko Aug 20 '20 at 19:35
  • It was written in the title, i just updatet the text to be confirm with the title. – TTho Einthausend Aug 20 '20 at 19:39