Javascript 一种安全的分割两个浮点数的方法?

Javascript 一种安全的分割两个浮点数的方法?,javascript,node.js,math,floating-point,ieee-754,Javascript,Node.js,Math,Floating Point,Ieee 754,划分两个IEEE 754浮点数最安全的方法是什么 在我的例子中,语言是JavaScript,但我想这并不重要。我们的目标是避免正常情况 我读过,可以使用“修正系数”(cf)(例如,将10提升到某个数字,例如10^10),如下所示: 但我不确定这是否会对分工产生影响 顺便说一句,我已经看过了关于堆栈溢出的其他浮点文章,但仍然没有找到一篇关于如何分割两个浮点数的文章。如果答案是加法和除法时处理浮点问题的解决方案没有区别,那么请回答这个问题 编辑: 我在评论中被问到了我指的是哪些陷阱,所以我想我也应该

划分两个IEEE 754浮点数最安全的方法是什么

在我的例子中,语言是JavaScript,但我想这并不重要。我们的目标是避免正常情况

我读过,可以使用“修正系数”(cf)(例如,将10提升到某个数字,例如10^10),如下所示:

但我不确定这是否会对分工产生影响

顺便说一句,我已经看过了关于堆栈溢出的其他浮点文章,但仍然没有找到一篇关于如何分割两个浮点数的文章。如果答案是加法和除法时处理浮点问题的解决方案没有区别,那么请回答这个问题

编辑:

我在评论中被问到了我指的是哪些陷阱,所以我想我也应该在这里为那些没有阅读评论的人补充一点:

当添加0.1和0.2时,您会期望得到0.3,但使用浮点运算,您会得到0.300000000000000004(至少在JavaScript中是这样)。这只是一个常见陷阱的例子


上面的问题在这里多次讨论堆栈溢出,但我不知道在除法时会发生什么,以及它是否与加法或乘法时发现的陷阱不同。可能是没有风险,在这种情况下,这将是一个非常好的答案。

浮点除法将产生与加法或乘法运算完全相同的“陷阱”,再多的预缩放也解决不了这个问题——最终结果就是最终结果,是IEEE-754中的内部表示导致了“问题”


解决方案是在计算过程中完全忘记这些精度问题,并尽可能晚地执行舍入,即仅在使用
.toFixed()将数字转换为字符串时显示计算结果
函数正是为此目的而提供的。

最安全的方法是简单地将它们分开。任何预定标都不会起任何作用,或增加舍入误差,或导致溢出或下溢

如果按二的幂进行预分级,可能会导致溢出或下溢,但在其他情况下不会对结果产生影响

如果您按任何其他数字预先定标,将在乘法中引入额外的舍入步骤,这可能会导致除法结果的舍入误差增加

如果简单地除以,结果将是与两个输入的比率最接近的可表示数字

IEEE 754 64位浮点数非常精确。几乎10^16中的一部分差异可以表示出来

有一些操作,例如floor和executecomparison,使得即使是极低意义的位也很重要。如果您一直在阅读有关浮点陷阱的文章,那么您应该已经看到了一些示例。避免这些。将输出四舍五入到适当的小数位数。小心地添加大小不同的数字

下面的程序演示了使用10到1e20的每个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;
    }
  }
}
.tofixed()不是分割浮点数的好方法。 使用javascript试试:4.11/100,你会感到惊讶

4.11 / 100 = 0.041100000000000005
并非所有浏览器都会得到相同的结果。 正确的解决方案是将浮点转换为整数:

parseInt(4.11 * Math.pow(10, 10)) / (100 * Math.pow(10, 10)) = 0.0411

你指的是什么具体的陷阱?你到底有什么问题?在一般情况下,最好是将两个js数除以另一个js数。
/
。避免“正常浮点陷阱”的目标太大,可能无法实现。您试图避免哪些具体问题?
a/b
的具体问题是什么?纯粹出于迷信而增加所谓的“修正系数”是一个相当可怕的想法已经把他们分开了!不-你会遇到与加法和乘法完全相同的问题-除法没有什么“特殊”或“不同”。所有“浮点错误”的唯一缓解措施是从概念上将存储的值与显示的值分离(即在输出时使用
.toFixed(n)
)。@HexedAgain:是的,真的<代码>a/b不会因为“无限”而消灭某人的资金。飞机不会因为“无限”而从天上掉下来。无穷大在浮点运算中不是一个特殊的值,它本身不会引起错误。当呈现无穷大时出现错误行为的软件是有缺陷的软件,句号。还要考虑到无穷远是一个比任何其他结果都好的结果。当有符号整数算术溢出时,结果是未定义的,但我很少看到有人这样说“
a*b
可能是灾难性的!”。
4.11 / 100 = 0.041100000000000005
parseInt(4.11 * Math.pow(10, 10)) / (100 * Math.pow(10, 10)) = 0.0411