假设我有两个值0 <= a < b <= 1
,我如何选择x
a <= x
<
b
最短的二进制扩展可能吗?
到目前为止,我的方法是采用a
和b
的二进制字符串,删除小数点,并在它们不同的第一个位置,将a
扩展为直到那一点。如果要消耗更多a
,请删除最后一位。最后,添加1
。
在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);
};
这有效,但我不相信它通常是正确。有什么想法吗?...
编辑我已经找到了一个无效的案例: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
编辑2 另一种算法是迭代2^-n
并检查其中是否有任何多个符合该区间。然而,这将更加昂贵。
答案 0 :(得分:4)
输入失败,如a = 0.1,b = 0.100001(二进制 - 即a = 0.5,b = 0.515625,十进制)。在这种情况下,正确的答案是0.1,但你的算法将产生0.11,这不仅不是最小长度,而且大于b: - (
你的数字检查看起来很好 - 问题是当你做出(正确)决定结束循环时,如果b的数字字符串更长,你构造错误的输出。修复它的一种简单方法是一次一个地输出数字,直到你看到一个不同的字符,你知道你必须包含当前字符。
还有一个提示:我不太了解Javascript,但我认为两个parseInt()
调用都是不必要的,因为您对u
或v
的任何操作都不需要算术。
<强> [编辑] 强>
以下是一些示例数字一次性代码,其中包含一些其他注意事项:
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's 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's 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;
};
答案 1 :(得分:3)
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;
}
}
代码迭代越来越大的二次幂分母(den
),直到找到一个支持适合该范围的值。
答案 2 :(得分:2)
我发布了另一个版本的代码。这试图修复已知问题:
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);
};
测试两种功能的简短功能:
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));
}
现在几乎没有结果:
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