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

时间:2018-01-18 21:18:22

标签: javascript floating-point precision rounding-error

在javascipt中我有像这样的浮动点“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”,或者如何使数字“b”更大小于“a”但比“a”更接近“a”。

编辑:
更具体:我正在寻找一个函数“makeLarger(a)”,它取一个数字“a”并返回一个数字“b”,其中“b> a”总是评估为真,“c> a&对于任何数字“c”,& c< b“将始终评估为false。还有一个类似的功能“makeSmaller(a)”。我希望“a”为任意数字,正数,负数或零。

3 个答案:

答案 0 :(得分:4)

假设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足够小,以便它适用于每个binade的极端。

因此,在不失一般性的情况下,考虑区间[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

这具有工作更大范围(任何正,非次正规实数)的优势。

对于次正规,您只需添加/减去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);
    }
 }

答案 1 :(得分:0)

您可以使用Big Number方法 - 将您的号码存储为其数字序列: 即G。 123... many digits here ...45[1, 2, 3, .., 4, 5]

所以你可以处理你的浮动数据,并且你的花车的精确度非常高。

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

答案 2 :(得分:0)

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

  1. 将浮动信息转换为字符串,您无需关心数字的大小(在合理范围内)。
  2. 找到小数点的索引。
  3. 从最后检索一组重要的数字(这里需要进行调整 - 类似于第一对不是由9或其他人引导的#0)
  4. 将它们转换为int并增加1
  5. 将第一个字符串中的数字替换为第二个字符串中的数字到var b
  6. 放置小数(在前一个索引处),强制转换为浮动。
  7. 有一些微调方面可以解决,但这将完成它。

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