Javascript。尽可能少地增加或减少浮动

Javascript. Increase or decrease float as little as possible

在 javascipt 中,我有这样的 av 浮点 "a":

var a = 5.;

现在我想要一个刚好比 "a" 大一点的新数字 "b"。我可以这样做:

var b = a + 1.e-10;

但是如果 "a" 是一个非常小的数字呢?

var a = 5.e-20;
var b = a + 1.e-10;

现在 "b" 比 "a" 大很多数量级。
此外,如果我使 "a" 和 "b" 之间的差异太小,则较大的 "a" 可能会导致差异被四舍五入。

如何使数字 "b" 大于任何数字 "a",但比任何其他大于 "a" 的数字更接近 "a",或者如何我是否制作一个小于 "a" 但比任何其他小于 "a".

的数字更接近 "a" 的数字 "b"

编辑:
太具体了:我正在寻找一个函数 "makeLarger(a)" 它需要一个数字 "a" 和 return 一个数字 "b" 其中 "b>a" 将始终计算为真并且 "c>a && c<b" 对任何数字 "c" 总是求值为 false。还有一个类似的功能"makeSmaller(a)"。我希望 "a" 是任何数字,正数、负数或零。

假设 a 是正的、真实的并且远离次正规(在这种情况下,大于 1.0020841800044864e-292),那么以下应该有效:

var u = Number.EPSILON/2 + Number.EPSILON*Number.EPSILON;
var b = a + a*u;

请注意 b = a * (1+u) 不会 起作用。 (例如,如果 a = 0.9999999999999998)。

基本思路是浮点数之间的差距大致成正比,只是步进递增(同一个binade内的所有数字都一样)。因此,挑战在于选择 u 足够小,以便它适用于每个二进制文件中的极端值。

所以不失一般性,考虑区间[1.0,2.0)中的数字a就足够了。我们需要确保

Machine.EPSILON/2 < a*u < Machine.EPSILON*3/2

这样最后的加法会朝着正确的方向舍入(而不是回到 a 或 2 个增量)。很容易证明上面定义的 u 满足这些属性。

要往下走你可以

var c = a - a*u;

P.S.: 另一种选择,虽然更难证明,是

var v = 1 - Machine.EPSILON/2;
var b = a / v; # upwards
var c = a * v; # downwards

这具有适用于更大范围(任何正的非次正规实数)的优势。

对于次正规,你可以 add/subtract Number.MIN_VALUE,所以把这些结合在一起你会得到:

function nextup(a) {
    var v = 1 - Number.EPSILON/2;
    if (a >= Number.MIN_VALUE / Number.EPSILON) {
        // positive normal
        return (a/v);
    } else if (a > -Number.MIN_VALUE / Number.EPSILON) {
        // subnormal or zero
        return (a+Number.MIN_VALUE);
    } else {
        // negative normal or NaN
        return (a*v);
    }
 }

 function nextdown(a) {
    var v = 1 - Number.EPSILON/2;
    if (a >= Number.MIN_VALUE / Number.EPSILON) {
        // positive normal
        return (a*v);
    } else if (a > -Number.MIN_VALUE / Number.EPSILON) {
        // subnormal or zero
        return (a-Number.MIN_VALUE);
    } else {
        // negative normal or NaN
        return (a/v);
    }
 }

您可以使用大数法——将您的号码存储为数字序列: e. G。 123... many digits here ...45 作为 [1, 2, 3, .., 4, 5]

所以你可以处理非常长的数字并且你的浮点数非常精确。

为此有几个 js 模块,例如http://jsfromhell.com/classes/bignumber

这可能是非正统的,但您可以执行以下操作:

  1. 将浮点数转换成字符串,你就不需要关心数字的大小了(在合理范围内)。
  2. 求小数点索引。
  3. 从末尾检索一组重要的数字(此处需要调整 - 类似于“直到第一对不是 0 的数字由 9 或诸如此类的东西”)
  4. 将它们转换为 int 并增加 1
  5. 将第一个字符串中的数字替换为第二个字符串中的数字到 var b
  6. 放置小数点(在前一个索引处),转换为浮点数。

有一些微调方面需要解决,但可以完成。

我不想为示例编写代码,但这很简单。