fortran fortran中文资料网
手气不错
Article

046.mod&Modulo_余数函数

modmodulo是Fortran用于计算余数的元素内在函数,两者在参数同号时常得到相同结果,但采用不同的商取整规则,因此负数参与时可能不同。mod常用于需要与趋零整数除法一致的余数计算;modulo适合在周期边界、循环下标、角度归一化等需要把负值映射到固定区间的情况中使用。

语法结构

remainder = mod(a, p)
remainder = modulo(a, p)
  • a是被除数,p是除数;两者必须同为整数或同为实数,并具有相同种类,且p不能为零。
  • mod(a,p)a-int(a/p)*p定义,商向零截断;非零结果的符号与a相同。
  • modulo(a,p)a-floor(a/p)*p定义,商向负无穷取整;非零结果的符号与p相同。
  • 两种结果的绝对值都小于abs(p)。当p为正数时,modulo满足0≤结果<p;若参数为整数,结果就是0到p-1中的整数。

本文代码

! 比较MOD与MODULO的符号规则,并演示周期下标映射。
program modModuloDemo
  implicit none

  integer, parameter :: dividends(*) = [7, -7, 7, -7]
  integer, parameter :: divisors(*) = [3, 3, -3, -3]
  integer :: i
  integer :: rawIndex, wrappedIndex

  print "(A)", "  a   p   mod(a,p)   modulo(a,p)"
  do i = 1, size(dividends)
    print "(2I4,2I11)", dividends(i), divisors(i), &
      mod(dividends(i), divisors(i)), modulo(dividends(i), divisors(i))
  end do

  rawIndex = -3
  wrappedIndex = modulo(rawIndex, 8)
  print "(/,A,I0,A,I0)", "周期下标:", rawIndex, " -> ", wrappedIndex
end program modModuloDemo

编译运行

(base) hong@hongdeMacBook-Pro 046.modModulo % gfortran exampleModModulo.f90
(base) hong@hongdeMacBook-Pro 046.modModulo % ./a.out
  a   p   mod(a,p)   modulo(a,p)
   7   3          1          1
  -7   3         -1          2
   7  -3          1         -2
  -7  -3         -1         -1

周期下标:-3 -> 5

现象分析

a=7p=3时,7除以3的截断商和向下取整商都是2,因此两个函数都计算7-2×3并得到1。参数同为负数时,-7除以-3的商为正数2,两种规则也再次得到相同余数-1。

a=-7p=3时,商为-2.333…。mod使用趋零商-2,计算-7-(-2)×3=-1;modulo使用向下取整商-3,计算-7-(-3)×3=2。两者相差一个除数,但分别满足自己的符号规则。

当除数改为-3时,mod(7,-3)仍跟随被除数得到1,而modulo(7,-3)跟随除数得到-2。由此可见,不能只用正除数理解两者差异。

周期长度为8时,合法下标为0到7。modulo(-3,8)得到5,使向左越过起点3格的下标回绕到区间内部;如果使用mod(-3,8)则仍得到-3,不能直接作为该周期区间的下标。

核心知识点

  • mod基于趋零商,非零余数跟随被除数符号;modulo基于向下取整商,非零余数跟随除数符号。
  • 两个参数为正数时结果相同不足以证明函数等价,比较时必须覆盖负被除数和负除数。
  • 正周期长度下的区间回绕通常使用modulo,因为结果稳定落在非负周期区间。
  • 除数不能为零;处理实数参数时还要考虑浮点舍入,不能把近似余数直接当作精确零。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注