I discovered the following code. I know, it looks less weird/exciting than this one using seemingly random numbers, but it seems to be more complex than this one using bit shifts on a large number:
long[] c = {130636800L, -5080148640L, 13802573088L, -14974335980L, 8683908340L,
-3006955245L, 651448014L, -89047770L, 7457160L, -349165L, 6998L};
for (int x = 0; x < 11; x++) {
long s = 0;
for (int i = 0; i < 11; i++)
s += c[i] * Math.pow(x, i);
System.out.print((char)(s / 1814400));
}
Output:
HELLO WORLD
How does it work? Is it some form of encryption or did anyone get mad constructing it?
Let's get into some math:
Solve the below equations and you get your answers. These equations have one unique solution as the number of equations equals the number of unknown variables.
Let c[0] = 72
, which is the ASCII value of 'H'.
For clarity: I've used ^
for raised to convention. Now solve:
1^0 * c[0] + 1^1 * c[1] + 1^2 * c[2] + 1^3 * c[3] + 1^4 * c[4] + 1^5 * c[5] + 1^6 * c[6] + 1^7 * c[7] + 1^8 * c[8] + 1^9 * c[9] + 1^10 * c[10] = 69
2^0 * c[0] + 2^1 * c[1] + 2^2 * c[2] + 2^3 * c[3] + 2^4 * c[4] + 2^5 * c[5] + 2^6 * c[6] + 2^7 * c[7] + 2^8 * c[8] + 2^9 * c[9] + 2^10 * c[10] = 76
3^0 * c[0] + 3^1 * c[1] + 3^2 * c[2] + 3^3 * c[3] + 3^4 * c[4] + 3^5 * c[5] + 3^6 * c[6] + 3^7 * c[7] + 3^8 * c[8] + 3^9 * c[9] + 3^10 * c[10] = 76
4^0 * c[0] + 4^1 * c[1] + 4^2 * c[2] + 4^3 * c[3] + 4^4 * c[4] + 4^5 * c[5] + 4^6 * c[6] + 4^7 * c[7] + 4^8 * c[8] + 4^9 * c[9] + 4^10 * c[10] = 79
5^0 * c[0] + 5^1 * c[1] + 5^2 * c[2] + 5^3 * c[3] + 5^4 * c[4] + 5^5 * c[5] + 5^6 * c[6] + 5^7 * c[7] + 5^8 * c[8] + 5^9 * c[9] + 5^10 * c[10] = 32
6^0 * c[0] + 6^1 * c[1] + 6^2 * c[2] + 6^3 * c[3] + 6^4 * c[4] + 6^5 * c[5] + 6^6 * c[6] + 6^7 * c[7] + 6^8 * c[8] + 6^9 * c[9] + 6^10 * c[10] = 87
7^0 * c[0] + 7^1 * c[1] + 7^2 * c[2] + 7^3 * c[3] + 7^4 * c[4] + 7^5 * c[5] + 7^6 * c[6] + 7^7 * c[7] + 7^8 * c[8] + 7^9 * c[9] + 7^10 * c[10] = 79
8^0 * c[0] + 8^1 * c[1] + 8^2 * c[2] + 8^3 * c[3] + 8^4 * c[4] + 8^5 * c[5] + 8^6 * c[6] + 8^7 * c[7] + 8^8 * c[8] + 8^9 * c[9] + 8^10 * c[10] = 82
9^0 * c[0] + 9^1 * c[1] + 9^2 * c[2] + 9^3 * c[3] + 9^4 * c[4] + 9^5 * c[5] + 9^6 * c[6] + 9^7 * c[7] + 9^8 * c[8] + 9^9 * c[9] + 9^10 * c[10] = 76
10^0 * c[0] + 10^1 * c[1] + 10^2 * c[2] + 10^3 * c[3] + 10^4 * c[4] + 10^5 * c[5] + 10^6 * c[6] + 10^7 * c[7] + 10^8 * c[8] + 10^9 * c[9] + 10^10 * c[10] = 68
Note that the number of unknowns are c[1]
to c[10]
, so 10. We know that c[0] = 72
, so it is not an unknown and the number of equations is 10.
Now we just multiply all numbers with 1814400, divide by the same in the answer, so it doesn't change anything or probably the answer found by solving the equations would not be whole numbers, so multiply by 1814400 to get whole numbers.
You can solve these equations by using this code for solving simultaneous equations of any order.
Inspired by the answer from user9823668, I found another way on how to reverse the calculation. The inner loop of the code (including the division from the output line) basically represents the following polynomial:
This polynomial is calculated for the values 0 to 10 in the outer loop of the code and yields the resulting ASCII characters. So the question is: How to fit a polynomial through given consecutive data points?
One of my search results points to the term Newton polynomial. This is a so-called interpolation polynomial for a given set of data points. As the polynomial is calculated for the values 0 to 10, we have the special case of xi = i here. Thus, in order to construct the above polynomial, we have to calculate some binomial coefficients.
At first we have to calculate the divided differences on the data points (i.e. the ASCII-encoded function output):
0: H = 72
1: E = 69 -3
2: L = 76 7 10
3: L = 76 0 -7 -17
4: O = 79 3 3 10 27
5: = 32 -47 -50 -53 -63 -90
6: W = 87 55 102 152 205 268 358
7: O = 79 -8 -63 -165 -317 -522 -790 -1148
8: R = 82 3 11 74 239 556 1078 1868 3016
9: L = 76 -6 -9 -20 -94 -333 -889 -1967 -3835 -6851
10: D = 68 -8 -2 7 27 121 454 1343 3310 7145 13996
Then, the topmost entries in each column are the coefficients that we need to construct the interpolating polynomial:
72
- 3 / 1 x
+ 10 / 2 x(x-1)
- 17 / 6 x(x-1)(x-2)
+ 27 / 24 x(x-1)(x-2)(x-3)
- 90 / 120 x(x-1)(x-2)(x-3)(x-4)
+ 358 / 720 x(x-1)(x-2)(x-3)(x-4)(x-5)
- 1148 / 5040 x(x-1)(x-2)(x-3)(x-4)(x-5)(x-6)
+ 3016 / 40320 x(x-1)(x-2)(x-3)(x-4)(x-5)(x-6)(x-7)
- 6851 / 362880 x(x-1)(x-2)(x-3)(x-4)(x-5)(x-6)(x-7)(x-8)
+ 13996 / 3628800 x(x-1)(x-2)(x-3)(x-4)(x-5)(x-6)(x-7)(x-8)(x-9)
Here, the denominators represents n! (see the special case). By expanding this formula (e.g. by using WolframAlpha), you get the polynomial shown above. In case anyone wonders, the polynomial looks as follows:
来源:https://stackoverflow.com/questions/50451537/why-does-this-code-using-math-pow-print-hello-world