Tho*_*son 0 javascript math floating-point ieee-754 node.js
划分两个IEEE 754浮点数的最安全的方法是什么?
就我而言,语言是JavaScript,但我想这并不重要.目标是避免正常的浮点陷阱.
我已经读过,人们可以使用"修正系数"(cf)(例如10提升到某个数字,例如10 ^ 10),如下所示:
(a * cf) / (b * cf)
Run Code Online (Sandbox Code Playgroud)
但我不确定这会对分裂产生影响吗?
顺便说一下,我已经看过Stack Overflow上的其他浮点帖子了,我还没有找到关于如何划分两个浮点数的单一帖子.如果答案是在添加和分割时解决浮点问题的解决方案之间没有区别,那么请回答一下.
编辑:
我在评论中已经被问到我所指的哪些陷阱,所以我想我也会在这里为那些没有阅读评论的人添加快速说明:
当加0.1和0.2时,你会得到0.3,但是使用浮点运算得到0.30000000000000004(至少在JavaScript中).这只是常见陷阱的一个例子.
上面的问题在Stack Overflow上讨论了很多次,但我不知道分割时会发生什么,如果它与添加或乘法时发现的陷阱不同.可能没有风险,在这种情况下,这将是一个非常好的答案.
最安全的方法是简单地划分它们.任何预定标记都将无效,或增加舍入误差,或导致上溢或下溢.
如果使用2的幂进行预分频,则可能导致上溢或下溢,但结果不会产生差异.
如果按任何其他数字预缩放,则会在乘法上引入其他舍入步骤,这可能会导致除法结果的舍入误差增加.
如果简单地除以,结果将是与两个输入的比率最接近的可表示数字.
IEEE 754 64位浮点数非常精确.可以表示几乎10 ^ 16中的一个部分的差异.
有一些操作,例如地板和精确比较,甚至使极低的重要性位变得重要.如果您一直在阅读浮点陷阱,您应该已经看过例子.避免那些.将输出舍入到适当的小数位数.小心添加非常不同的数量.
以下程序演示了使用10到10e20的每个10的幂作为比例因子的效果.大多数得到的结果与不乘以6.0相同,这也是有理数算术结果.有些得到稍大的结果.
您可以通过改变初始化为不同部门的问题进行试验a
和b
.在四舍五入到双精度之后,程序打印出它们的确切值.
import java.math.BigDecimal;
public class Test {
public static void main(String[] args) {
double mult = 10;
double a = 2;
double b = 1.0 / 3.0;
System.out.println("a=" + new BigDecimal(a));
System.out.println("b=" + new BigDecimal(b));
System.out.println("No multiplier result="+(a/b));
for (int i = 0; i < 20; i++) {
System.out.println("mult="+mult + " result="+((a * mult) / (b * mult)));
mult *= 10;
}
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
a=2
b=0.333333333333333314829616256247390992939472198486328125
No multiplier result=6.0
mult=10.0 result=6.000000000000001
mult=100.0 result=6.000000000000001
mult=1000.0 result=6.0
mult=10000.0 result=6.000000000000001
mult=100000.0 result=6.000000000000001
mult=1000000.0 result=6.0
mult=1.0E7 result=6.000000000000001
mult=1.0E8 result=6.0
Run Code Online (Sandbox Code Playgroud)
浮点除法将产生与加法或乘法运算完全相同的"陷阱",并且没有任何预缩放量可以解决它 - 最终结果是最终结果,它是IEEE-754中内部表示导致的"问题".
解决方案是在计算过程中完全忘记这些精度问题,并尽可能晚地执行舍入,即仅在显示计算结果时,在使用.toFixed()
精确提供的函数将数字转换为字符串的位置执行舍入为了这个目的.
归档时间: |
|
查看次数: |
903 次 |
最近记录: |