Floating point 朱莉娅:如何处理浮点的精确性

Floating point 朱莉娅:如何处理浮点的精确性,floating-point,julia,precision,Floating Point,Julia,Precision,我遇到过浮点数精度不精确的情况。正如我在下面的代码的简化版本中所展示的,我在相同的场景中计算一个和,在最后的小数中我得到不同的值。这是有关的 我想知道是否有任何方法可以解决这个问题,例如某种截断 s1 = zero(Float64) s = zero(Float64) for a in 1:10000 for k in 1:4 temp=log(1e-5) s1+=temp s +=temp end end s2 = zero(Fl

我遇到过浮点数精度不精确的情况。正如我在下面的代码的简化版本中所展示的,我在相同的场景中计算一个和,在最后的小数中我得到不同的值。这是有关的

我想知道是否有任何方法可以解决这个问题,例如某种截断

s1 = zero(Float64)
s = zero(Float64)
for a in 1:10000
    for k in 1:4
        temp=log(1e-5)
        s1+=temp
        s +=temp
    end
end
s2 = zero(Float64)
for a in 1:10000
    for k in 1:4
        temp = log(1e-5)
        s2+=temp
        s+=temp
    end
end

s1+s2 == s     ###FALSE
s < s1+s2      ###TRUE
s1=0(浮点64)
s=零(浮点数64)
以1:10000的比例计算
1:4中的k
温度=对数(1e-5)
s1+=温度
s+=温度
结束
结束
s2=零(浮点数64)
以1:10000的比例计算
1:4中的k
温度=对数(1e-5)
s2+=温度
s+=温度
结束
结束
s1+s2==s####假
s
浮点加法不是:由于中间舍入,更改加法顺序可能会产生细微不同的结果

您可以做以下几件事:

  • 使用更精确的求和算法,例如。这在Julia中可用作
    sum\u kbn
  • julia>sum_kbn(a=1:10000,k=1:4的对数(1e-5))
    -460517.01859880914
    

  • 检查近似相等而不是精确相等。如Gnimuc所述,您可以使用
    isapprox
    (也可通过中缀
    )。这接受分别用于指定绝对和相对公差的
    atol
    rtol
    可选参数
  • s1+s2≈ s
    

    浮点加法不是:由于中间舍入,更改加法顺序可能会产生细微不同的结果

    您可以做以下几件事:

  • 使用更精确的求和算法,例如。这在Julia中可用作
    sum\u kbn
  • julia>sum_kbn(a=1:10000,k=1:4的对数(1e-5))
    -460517.01859880914
    

  • 检查近似相等而不是精确相等。如Gnimuc所述,您可以使用
    isapprox
    (也可通过中缀
    )。这接受分别用于指定绝对和相对公差的
    atol
    rtol
    可选参数
  • s1+s2≈ s
    

    浮点64表示IEEE 754格式的数字。在64位中,尾数占52位。这意味着精度约为15位小数

    在第一次循环之后,
    s1
    s
    应该是相同的

    差异发生在第二个循环体中。
    temp
    中的数字始终相同<当第一次进入第二个循环的循环体时,code>s
    几乎是
    temp*40000.0
    。将
    temp
    添加到
    s
    时,会导致
    temp
    的最后4.5位数字丢失。这就是差异的原因,因为
    s2
    将为零,添加
    temp
    将使用
    temp
    的所有数字

    顺便说一下,
    s、s1+s2
    中没有一个(以编程方式)与
    temp*80000.0
    相同(从数学上讲,所有3个数字都应该相同)

    因此,为了减少数字错误,请遵守规则

    • 更喜欢乘法,它们保持精度
    • 数字越相等,相加就越精确。您按照
      a/b
      的顺序丢失了精度(而
      a=abs(a),b=abs(b),a>b,b!=0
    • 相减的数字越相等,精度就越低。按照前导公共数字或更确切地说是位的顺序降低精度
    这并不是julia的具体问题,它将发生在使用IEEE 754的所有语言中(C/C++double,Java double,julia Float64,…)


    浮点64表示IEEE 754格式的数字。在64位中,尾数占52位。这意味着精度约为15位小数

    在第一次循环之后,
    s1
    s
    应该是相同的

    差异发生在第二个循环体中。
    temp
    中的数字始终相同<当第一次进入第二个循环的循环体时,code>s
    几乎是
    temp*40000.0
    。将
    temp
    添加到
    s
    时,会导致
    temp
    的最后4.5位数字丢失。这就是差异的原因,因为
    s2
    将为零,添加
    temp
    将使用
    temp
    的所有数字

    顺便说一下,
    s、s1+s2
    中没有一个(以编程方式)与
    temp*80000.0
    相同(从数学上讲,所有3个数字都应该相同)

    因此,为了减少数字错误,请遵守规则

    • 更喜欢乘法,它们保持精度
    • 数字越相等,相加就越精确。您按照
      a/b
      的顺序丢失了精度(而
      a=abs(a),b=abs(b),a>b,b!=0
    • 相减的数字越相等,精度就越低。按照前导公共数字或更确切地说是位的顺序降低精度
    这并不是julia的具体问题,它将发生在使用IEEE 754的所有语言中(C/C++double,Java double,julia Float64,…)


    可能重复使用<代码>≈(\approx)而不是
    =
    <代码>s1+s2≈ s#=>true非重复:这是关于解决特定语言中浮点问题的策略,而不是它发生的原因。可能重复使用
    (\approx)而不是
    =
    <代码>s1+s2≈ s#=>true
    不是重复:这是关于解决特定语言中浮点问题的策略,而不是它发生的原因。
    s1 = zero(Float64)
    s = zero(Float64)
    for a in 1:40000
        temp=log(1e-5)
        s1+=temp
        s +=temp 
    end
    s2 = zero(Float64)
    for a in 1:40000
        temp = log(1e-5)
        s2+=temp
        s+=temp
    end
    
    sm = 80000.0 * log(1e-5);
    println(s1+s2 == s)
    println(s < s1+s2)
    println(s == sm)
    println(s1+s2 == sm)
    
    println(s1+s2)
    println(sm)
    println(s)
    
    false
    true
    false
    false
    -921034.0371971375
    -921034.0371976183
    -921034.0371986133