I'm mathematically trying to determine the shortest sequence of moves to reach a desired numerical result. I have two functions, both of which multiply a number by 2, and minus the value of the other number.
I've included my code so far, which has me manually calling the two functions to obtain the desired result; however, I would like help figuring out the logic to do this automatically with a loop.
function findShortestSequence(number) {
let left = 0;
let right = 1;
let moves = [];
const moveLeft = () => {
moves.push('L');
left = 2 * left - right;
}
const moveRight = () => {
moves.push('R');
right = 2 * right - left;
}
moveLeft();
moveLeft();
moveRight();
moveLeft();
console.log(left, right, moves);
}
findShortestSequence(-11)
I was just looking at -11, and considering 11 being 1011 in binary, which resembles your manual solution of LLRL, just backwards. Tests suggest that this may be the key for negative numbers: get their absolute value, and start shifting towards the right until it becomes zero. When you shift out an 1, move to the left, when you shift out a 0, move to the right. The last step will be a left-move, and the result goes into left.
Then I just checked what about positive numbers, simply swapping the moves (because leaving them in place would provide the negative result) and it appeared to generate one number above the goal. So I just subtracted one from the original and it started to work. Of course this time the last step is going to be a right-move, and result goes into right:
function findShortestSequence(number) {
let org = number;
if(number<=0)number=-number; // work with absolute values when input is not positive
else number--; // work with one less, if input is positive
let left = 0;
let right = 1;
let moves = [];
const moveLeft = () => {
moves.push('L');
left = 2 * left - right;
}
const moveRight = () => {
moves.push('R');
right = 2 * right - left;
}
if(org<=0)
while(number!=0){
if(number&1)moveLeft();
else moveRight();
number>>=1;
}
else
while(number!=0){
if(number&1)moveRight();
else moveLeft();
number>>=1;
}
console.log(org, left, right, moves.join(''), (org==left)||(org==right));
}
for(var i=-20;i<=20;i++)
findShortestSequence(i);
While I do not chase to provide a full explanation, I can provide some pieces which one may find useful:
10001001 (137) and 1001 is the fixer, then multiply by 2 shifts everything to the left (100010010, 274), and if you want to keep that 0001001 part in its original place, subtracting the fixer "locally divides" that part back to its original place (100010010-1001=100001001), this is more or less what moveRight does to positive numbers1001 becomes 10010, and subtracting 10001001 fixes back 1001 on the lower places, and also introduces that 1 from the beginning at high places. The nasty part is that 10001001 is clearly larger than 10010, so the result is a negative number, and in fact the fixer (left in case of a positive target number) has never been 1001, because at its very first update ever, it becomes "2*0-something" (where "something" is a positive number, as right starts from 1). Indeed, looking at the example loop, left always seems to end up being non-positive, and right seems to be non-negativeright) is non-negative, and positive*2-negative also stays positive:...11110001001 (left) and 1001 (right), ...11110001001*2 is ...111100010010, and ...111100010010-1001=...111100001001, first part of the mission is accomplished (keeping the 1001 pattern in place)...1110010001001 later (after 2 moveLeft-s), then moveRight really does 1001*2=10010, 10010-...11110001001(-119)=10001001, which is exactly what is needed to extend the 1001 pattern into 10001001 for the 8 lowest places)moveRight, if left remains 0 all the time, right jumps to the next power of two each step, so ceil(log2(number)) steps are needed to reach or surpass the given number, which equals to the number of significant binary digits required represent the number, which equals the steps taken by the loop.I think I came to the same conclusion as tevemadar. Here it is in code:
function confirm(str, n){
let l = 0;
let r = 1;
let i = 0;
while(str[i]){
if (str[i++] == 'L')
l = 2*l - r;
else
r = 2*r - l;
}
if ([l, r].includes(n))
return true;
return false;
}
function f(n){
if ([0, 1].includes(n))
return '';
else if (n > 1)
return (n - 1)
.toString(2)
.split('')
.map(x => x & 1 ? 'R' : 'L')
.reverse()
.join('');
else
return (-n)
.toString(2)
.split('')
.map(x => x & 1 ? 'L' : 'R')
.reverse()
.join('');
}
for (let i=-11; i<=11; i++){
fi = f(i);
console.log(i + ': ' + fi + ', ' + confirm(fi, i));
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With