NCL Website header
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