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
这可能是非正统的,但您可以执行以下操作:
- 将浮点数转换成字符串,你就不需要关心数字的大小了(在合理范围内)。
- 求小数点索引。
- 从末尾检索一组重要的数字(此处需要调整 - 类似于“直到第一对不是 0 的数字由 9 或诸如此类的东西”)
- 将它们转换为 int 并增加 1
- 将第一个字符串中的数字替换为第二个字符串中的数字到 var b
- 放置小数点(在前一个索引处),转换为浮点数。
有一些微调方面需要解决,但可以完成。
我不想为示例编写代码,但这很简单。
在 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
这可能是非正统的,但您可以执行以下操作:
- 将浮点数转换成字符串,你就不需要关心数字的大小了(在合理范围内)。
- 求小数点索引。
- 从末尾检索一组重要的数字(此处需要调整 - 类似于“直到第一对不是 0 的数字由 9 或诸如此类的东西”)
- 将它们转换为 int 并增加 1
- 将第一个字符串中的数字替换为第二个字符串中的数字到 var b
- 放置小数点(在前一个索引处),转换为浮点数。
有一些微调方面需要解决,但可以完成。
我不想为示例编写代码,但这很简单。