NCL Home > Documentation > Functions > General applied math

# mod

Remainder function which emulates the Fortran "mod" intrinsic function.

Available in version 4.3.0 and later.

## Prototype

load "\$NCARG_ROOT/lib/ncarg/nclscripts/csm/contributed.ncl"  ; This library is automatically loaded
; from NCL V6.2.0 onward.
; No need for user to explicitly load.

function mod (
n  : numeric,  ; integer, float, double
m  : numeric
)

return_val  :  same type and shape as n

## Arguments

n

Scalar or array variable of type integer, float, double.

m

Scalar or array variable. If an array it must be the same shape as n. Although not required, it is best if it is the same type as n.

## Description

NCL has a modulus algebraic operator, % , which requires that the arguments be integers. The mod function is more general. The results are the same as those of the GNU "gfortran" compiler. While the function allows mixed types, it is best to always use n and m of the same type.

## Examples

Example 1: Sample usage: numeric results and return types. Note that the returned value is the same numeric type and sign as argument n.

17 % 3     = 2     NCL modulus syntax (integers only)

mod(17,3)         = 2     type= integer
mod(17.5,5.5)     = 1     type= float
mod(17.5d0,5.5)   = 1     type= double
mod(17.5d0,5.5d0) = 1     type= double
mod(17.5,5.5d0)   = 1     type= float

mod(17.5, 5 )     = 2.5   type= float
mod(17  ,5.5)     = 2     type= integer

mod(-17,3)        = -2    type= integer
mod(-17.5,5.5)    = -1    type= float
mod(-17.5d0,5.5)  = -1    type= double
mod(-17.5d0,5.5d0)= -1    type= double
mod(-17.5,5.5d0)  = -1    type= float

mod(-17.5, 5 )    = -2.5  type= float
mod(-17  ,5.5)    = -2    type= integer

mod(17,-3)        = 2     type= integer
mod(17.5,-5.5)    = 1     type= float
mod(17.5d0,-5.5)  = 1     type= double
mod(17.5d0,-5.5d0)= 1     type= double
mod(17.5,-5.5d0)  = 1     type= float

mod(17.5, -5 )    = 2.5   type= float
mod(17  ,-5.5)    = 2     type= integer

Example 2: This example is based on a response by David Allured (NOAA-CIRES) to an ncl-talk@ucar.edu query.

Consider a set of values which are cyclic. Two common examples would be angular coordinates for a circle and longitudes on the entire globe. Let's say data are to be uniquely partitioned into four quadrants: (i) 0-90; (ii) 90-180; (c) 180-270; (d) 270-onward. How can the appropriate indices be determined that account for the cyclic condition?

dlon   = 10
nlon   = 360/dlon
lon    = fspan(0, 350,nlon)                                 ; 0,10,20,....,330,340,350
theta  =  2*dlon
lon_offset = mod (lon + 360 - theta, 360)
print(lon_offset)                                           ;  340,350, 0, 10,..., 320,330

iq1 = ind (lon_offset .lt. 90)                              ; [9]: 2,3,...,8,9,10
iq2 = ind (lon_offset .ge. 90   .and. lon_offset .lt. 180)  ; [9]: 11,12,...,18,19
iq3 = ind (lon_offset .ge. 180 .and. lon_offset .lt. 270)   ; [9]: 20,21,...,27,28
iq4 = ind (lon_offset .ge. 270)                             ; [9]: 0, 1,29,30,...,34,35

The above method effectively converts the NCL mod function to a true mathematical modulo function for cyclic applications. Understand the difference here:

https://en.wikipedia.org/wiki/Modulo_operation

Note: If an application requires overlapping index points in some cases change .lt. to .le. in the iq1/iq2/iq3 statements.

Example 3: The following function returns the unique indices for a user specified number of angular segments:

undef("mod_cyclic_ind")
function mod_cyclic_ind(x[*]:numeric, nsec[1]:integer)
;
; Return unique index values for cyclic sequence.
;
; Nomenclature:
;   x    - angles or longitides
;   nsec - number of sections. EG: nsec=4 means quadrants,
;
; https://www.ncl.ucar.edu/Document/Functions/Contributed/mod.shtml
; Examples 2 and 3
;
local nx, dx, ang, theta, xcyc, nind, icyc
begin
nx = dimsizes(x)
if (nx.lt.3) then
print("mod_cyclic_ind: more than 3 values needed: nx="+nx)
exit
end if

dx = x(1)-x(0)
if (.not.all(x(1:)-x(0:nx-2)).eq.dx) then
print("mod_cyclic_ind: values not equally spaced")
exit
end if

ang   = 360/nsec
theta = 2*dx
xcyc  = mod (x+360-theta, 360) ; extra 360 degrees prevents negative index values
; for initial (first) section.
nind  = nx/nsec
icyc  = new( (/nsec,nind/), integer, "No_FillValue")

icyc(0,:)    = ind (xcyc .lt. ang)
do n=1,nsec-2
icyc(n,:) = ind(xcyc.ge.(n*ang) .and. xcyc.lt.((n+1)*ang))
end do
icyc(nsec-1,:) =  ind(xcyc .ge. ang*(nsec-1))

icyc@long_name = "cyclic indices"    ; meta data for completeness
icyc!0 = "section"
icyc!1 = "index"
return(icyc)
end

;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;             MAIN
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
dlon   = 10
nlon   = 360/dlon
lon    = fspan(0, 350,nlon)       ; 0,10,20,....,330,340,350

;---test function with nsec=4 :---> Example 2 (quadrants)

IQ     =  mod_cyclic_ind(lon, 4)
printVarSummary(IQ)
print("")
print(IQ(0,:)+"  "+IQ(1,:)+"  "+IQ(2,:)+"  "+IQ(3,:))
print("---")

;---test function with nsec=12
IQ    :=  mod_cyclic_ind(lon,12)       ;  := is reassignment operator
printVarSummary(IQ)
print("")
print(IQ(0,:)+"  "+IQ(1,:)+"  "+IQ( 2,:)+"  "+IQ( 3,:)+"  "+ \
IQ(4,:)+"  "+IQ(5,:)+"  "+IQ( 6,:)+"  "+IQ( 7,:)+"  "+ \
IQ(8,:)+"  "+IQ(9,:)+"  "+IQ(10,:)+"  "+IQ(11,:))

The output for the above code is:

Variable: IQ
Type: integer
Total Size: 144 bytes
36 values
Number of Dimensions: 2
Dimensions and sizes:	[section | 4] x [index | 9]
Coordinates:
Number Of Attributes: 1
long_name :	cyclic indices

(0)	2  11  20  0
(1)	3  12  21  1
(2)	4  13  22  29
(3)	5  14  23  30
(4)	6  15  24  31
(5)	7  16  25  32
(6)	8  17  26  33
(7)	9  18  27  34
(8)	10 19  28  35

(0)	---

Variable: IQ
Type: integer
Total Size: 144 bytes
36 values
Number of Dimensions: 2
Dimensions and sizes:	[section | 12] x [index | 3]
Coordinates:
Number Of Attributes: 1
long_name :	cyclic indices

(0)	2  5  8  11  14  17  20  23  26  29  32  0
(1)	3  6  9  12  15  18  21  24  27  30  33  1
(2)	4  7  10 13  16  19  22  25  28  31  34  35