使用CEILING而不受舍入误差的影响

时间:2016-10-11 03:09:48

标签: fortran fortran90 intrinsics

我正在尝试使用内在函数'CEILING',但是舍入错误使得有时难以得到我想要的东西。示例代码非常简单:

PROGRAM MAIN

  IMPLICIT NONE

  INTEGER, PARAMETER        ::      ppm_kind_double = KIND(1.0D0)
  REAL(ppm_kind_double)     ::      before,after,dx

  before = -0.112
  dx = 0.008
  after = CEILING(before/dx)

  WRITE(*,*) before, dx, before/dx, after

  END

我得到了结果:enter image description here

我在代码中给'before'和'dx'的值仅用于演示。例如,对于/ dx = -13.5之前的那些,我想使用CEILING来获得-13。但是对于我展示的图片,我实际上想得到-14。我考虑过使用像

这样的论点
 IF(ABS(NINT(before/dx) - before/dx) < 0.001)

但那并不美丽。有没有更好的方法来做到这一点?

更新

我很惊讶地发现,如果我将变量设置为ppm_kind_double中的常量,则不会出现问题。所以我猜这个'舍入错误'只会在我使用的机器的舍入精度的位数大于ppm_kind_double中定义的位数时发生。我实际上在一个集群上运行我的程序(不是这个演示代码),我不知道它的机器精度。那么也许这台机器的四倍精度会导致问题呢?

将常量设置为双精度后:

before = -0.112_ppm_kind_double
dx = 0.008_ppm_kind_double

enter image description here

2 个答案:

答案 0 :(得分:0)

这有点棘手,因为你永远不知道舍入误差来自何处。如果dx只比0.008稍微大一点,则除法before/dx可能仍会四舍五入到相同的值,但现在-13将是正确答案。

那就是说,我所看到的最常见的方法就是之前的值轻微推向。像这样:

program sign_test
    use iso_fortran_env
    implicit none
    real(kind=real64) :: a, b
    integer(kind=int32) :: c
    a = -0.112
    b = 0.008
    c = my_ceiling(a/b)
    print*, a, b, c
contains
    function my_ceiling(v)
        implicit none
        real(kind=real64), intent(in) :: v
        integer(kind=int32) :: my_ceiling
        my_ceiling = ceiling(v - 1d-6, kind=int32)
    end function my_ceiling
end program sign_test

这对绝大多数价值观都没有任何影响,但现在有一些价值会超出预期。

答案 1 :(得分:0)

请注意,如果您的实际意义上是&#34;确切的&#34;要达到指定的精度,您可以执行以下操作:

public boolean isObjectStillValid(Object source, HttpHeaders headers) {

    Assert.notNull(source, "Source object must not be null!");
    Assert.notNull(headers, "HttpHeaders must not be null!");

    if (headers.getIfModifiedSince() == -1) {
        return false;
    }

    //THE WRAPPER IS NULL IF NO AUDITING ANNOTATIONS PRESENT
    AuditableBeanWrapper wrapper = auditableBeanWrapperFactory.getBeanWrapperFor(source);
    long current = wrapper.getLastModifiedDate().getTimeInMillis() / 1000 * 1000;

    return current <= headers.getIfModifiedSince();
}

这适用于您的示例..您还没有说出您对这两个值的正面评价等等,因此您可能需要稍微努力。