Find the shortest binary string in a given interval

Let's say I have two values 0 <= a < b <= 1 , how can I choose x so that a <= x < b shortest binary extension is possible?

So far, my approach has been to take the binary strings a and b , with the decimal point removed, and, firstly, they are different, expand a to this point. If you need more than a , split the last bit. Finally add 1 .

In JavaScript:

 var binaryInInterval = function(a, b) { if (a < 0 || b > 1 || a >= b) return undefined; var i, u, v, x = ''; a = a.toString(2).replace('.', ''); b = b.toString(2).replace('.', ''); for (i = 0; i < Math.max(a.length, b.length); i++) { u = parseInt(a.substr(i, 1), 10) || 0; v = parseInt(b.substr(i, 1), 10) || 0; x += u.toString(); if (u != v) { if (i + 1 < a.length) x = x.slice(0, -1); x += '1'; break; } } return '0.' + x.substr(1); }; 

This works, but I'm not sure if this is generally correct. Any thoughts? ...


EDIT I already found a case that does not work correctly: P

 binaryInInterval(0.25, 0.5) = '0.1' 0.25 0.01 0.5 0.1 ^ Difference but a hasn't been fully consumed so we strip 00 to 0 before adding 1 

EDIT 2 . An alternative algorithm would be to iterate through 2^-n and check if any multiple matches this interval within the interval. However, that would be more expensive.

+7
source share
3 answers
 function bin(a, b) { var den = 1; while (true) { var bint = Math.floor(b); if (bint == b) bint--; if (a <= bint) { return bint / den; } den *= 2; a *= 2; b *= 2; } } 

This code iterates through the larger and larger denominators of the power of two ( den ) until it finds one that supports the value that matches the range.

+3
source

It will fail for inputs such as a = 0.1, b = 0.100001 (in binary, i.e. a = 0.5, b = 0.515625 in decimal). In this case, the correct answer will be 0.1, but instead, your algorithm will produce 0.11 instead, which is not only not minimal, but also greater than b: - (

Your digit check looks good to me - the problem is that when you made the (right) decision to end the loop, you are building the wrong output if the length of line b is longer. One easy way to fix this is to print the numbers in turn, while you see another character, you know that you must include the current character.

One more tip: I don't know Javascript, but I think both calls to parseInt() not needed, since nothing you do with u or v actually requires arithmetic.

[EDIT]

Here is an example of a time-digit code that includes several other considerations:

 var binaryInInterval = function(a, b) { if (a < 0 || b > 1 || a >= b) return undefined; if (a == 0) return '0'; // Special: only number that can end with a 0 var i, j, u, v, x = ''; a = a.toString(2).replace('.', ''); b = b.toString(2).replace('.', ''); for (i = 0; i < Math.min(a.length, b.length); i++) { u = a.substr(i, 1); v = b.substr(i, 1); if (u != v) { // We know that u must be '0' and v must be '1'. // We therefore also know that u must have at least 1 more '1' digit, // since you cannot have a '0' as the last digit. if (i < b.length - 1) { // b has more digits, meaning it must // have more '1' digits, meaning it must be larger than // x if we add a '1' here, so it safe to do that and stop. x += '1'; // This is >= a, because we know u = '0'. } else { // To ensure x is >= a, we need to look for the first // '0' in a from this point on, change it to a '1', // and stop. If a only contains '1 from here on out, // it suffices to copy them, and not bother appending a '1'. x += '0'; for (j = i + 1; j < a.length; ++j) { if (a.substr(j, 1) == '0') { break; } } } break; // We're done. Fall through to fix the binary point. } else { x += u; // Business as usual. } } // If we make it to here, it must be because either (1) we hit a // different digit, in which case we have prepared an x that is correct // except for the binary point, or (2) a and b agree on all // their leftmost min(len(a), len(b)) digits. For (2), it must therefore be // that b has more digits (and thus more '1' digits), because if a // had more it would necessarily be larger than b, which is impossible. // In this case, x will simply be a. // So in both cases (1) and (2), all we need to do is fix the binary point. if (x.length > 1) x = '0.' + x.substr(1); return x; }; 
+4
source

I am sending another version of the code. This is trying to solve known problems:

  var binaryInIntervalNew = function(inpA, inpB) { if (inpA < 0 || inpB > 1 || inpA >= inpB) return undefined; var i, u, v, x = ''; a = inpA.toString(2).split('.'); b = inpB.toString(2).split('.'); a = a[a.length - 1]; b = b[b.length - 1]; for (i = 0; i < Math.min(a.length, b.length); i++) { u = a.substr(i, 1); v = b.substr(i, 1); if (u !== v) { // x cannot become equal to b, let us verify that if ((i+1) === b.length) { x += '01'; } else { x += '1'; } break; } else { x += u; } // console.log("x: " + x + " i:" + i); } x = '0.' + x; return parseFloat(x); }; 

Short-term function to test both functions:

 function bin(a, b) { console.log("a:" + a.toString(2)); console.log("b:" + b.toString(2)); if (binaryInIntervalNew) console.log("binaryInIntervalNew: " + binaryInIntervalNew(a, b)); if (binaryInInterval) console.log("binaryInInterval: " + binaryInInterval(a, b)); } 

Now there are several results:

 bin(1/16, 1/4); a:0.0001 b:0.01 binaryInIntervalNew: 0.001 binaryInInterval: 0.01 bin(.1, .2); a:0.0001100110011001100110011001100110011001100110011001101 b:0.001100110011001100110011001100110011001100110011001101 binaryInIntervalNew: 0.001 binaryInInterval: 0.001 bin(1/4, 1/2); a:0.01 b:0.1 b:0.1 binaryInIntervalNew: 0.01 binaryInInterval: 0.1 bin(.2, .5); a:0.001100110011001100110011001100110011001100110011001101 b:0.1 b:0.1 binaryInIntervalNew: 0.01 binaryInInterval: 0.1 bin(.0011, .1); a:0.00000000010010000001011011110000000001101000110110111000101111 b:0.0001100110011001100110011001100110011001100110011001101 b:0.0001100110011001100110011001100110011001100110011001101 binaryInIntervalNew: 0.0001 binaryInInterval: 0.0001 
+2
source

All Articles