Math and trigonometry functions

MOD

Matches all 152,669 recorded answers

Recorded: 152,432 in the answer bank and 237 workbook cells. How we measure this · See the Rust code

Local names in 40 languages
LanguageName in Excel
ArabicMOD
BulgarianMOD
CzechMOD
DanishREST
GermanREST
GreekMOD
English (Australia)MOD
English (United Kingdom)MOD
English (United States)MOD
SpanishRESIDUO
EstonianMOD
FinnishJAKOJ
FrenchMOD
HebrewMOD
CroatianMOD
HungarianMARADÉK
IndonesianMOD
ItalianMOD
JapaneseMOD
KoreanMOD
LithuanianMOD
LatvianMOD
NorwegianMOD
DutchREST
PolishMOD
Portuguese (Brazil)MOD
Portuguese (Portugal)RESTO
RomanianMOD
RussianОСТАТ
SlovakMOD
SlovenianMOD
Serbian (Latin)MOD
SwedishMOD
ThaiMOD
TurkishMOD
UkrainianMOD
VietnameseMOD
Chinese (Simplified)MOD
Chinese (Hong Kong)MOD
Chinese (Traditional)MOD

Names from Microsoft's support site.

What it does

MOD(number, divisor)

MOD(number, divisor) returns the floored remainder. For ordinary nonzero remainders the result follows the divisor’s sign. Noninteger inputs are allowed. The mathematical identity is number-divisor*INT(number/divisor).

Try it

Input cells (optional)

Example: {"B2": 3, "B3": 4}. A1 holds the formula. Other cells need values before a formula can read them.

Enter a formula, then calculate.

Runs locally in your browser with OneCalc. Its answer may differ from Excel. Use English function names and commas between arguments.

=MOD(-7,3) returns 2: -7 = (-3)*3+2. =MOD(7,-3) returns -2. With binary64 decimal inputs, the recorded MOD(10,0.1) is 0.09999999999999945, not zero.

Quirks

A zero divisor gives #DIV/0!. Recorded Excel returns #NUM! when the rounded quotient magnitude reaches 1.1259e12, although a mathematical remainder still exists. Tiny operands can return the wrong sign-adjusted magnitude or #NUM!; these are compatibility rules, not properties of mathematical modulo. The prior explanation that Excel necessarily subtracts two large approximate products is not supported by the later exact-remainder evidence.

MOD with tiny operands gives wrong signs and #NUM!, by a rule that fits every recorded row

MOD(n,d) takes the exact remainder r of n by d and adds d when their signs differ. Three things change when r is subnormal and its sign differs from d's. The result is #NUM! when |n/d| is 2^26 or more, or when d's low part under a Veltkamp split at 2^27 + 1 is subnormal. Otherwise, when |r| is below 2^-1026, the result is |d| + |r| with d's sign: the remainder is added where it should be taken away. A larger r takes the ordinary step. Any subnormal final result is #NUM!. So MOD(-(1+121*2^-52)*2^-983, 2^-983) returns +(1+121*2^-52)*2^-983, and MOD(2^-983, -(1+120*2^-52)*2^-983) returns #NUM!, where the exact answers are ordinary numbers.

Explanation (inferred): The rule is what is measured. Reading it as Veltkamp's split, the parts of a Dekker product of the count and the divisor, is an interpretation: a table over exponent and trailing zeros puts the boundary between exponents -1000 and -990 and at about 27 trailing zeros.

FormulaExcelMathematical value
MOD(-1.223247290044572e-296, 1.223247290044539e-296)
Excel 16.0 build 20430, Windows 64-bit, CPU not recorded in this capture
Inputs and reference value

Number supplied through a cell.

number: -1.223247290044572e-296
0x8280000000000079

divisor: 1.223247290044539e-296
0x0280000000000000

MOD(n,d) = n - d*INT(n/d) in exact rational arithmetic; the result is exactly representable.

1.223247290044572e-296
0x0280000000000079
1.2232472900445062e-296
0x027fffffffffff0e
MOD(1.223247290044539e-296, -1.2232472900445716e-296)
Excel 16.0 build 20430, Windows 64-bit, CPU not recorded in this capture
Inputs and reference value

Number supplied through a cell.

number: 1.223247290044539e-296
0x0280000000000000

divisor: -1.2232472900445716e-296
0x8280000000000078

MOD(n,d) = n - d*INT(n/d) in exact rational arithmetic; the result is exactly representable.

#NUM!-3.25938553492266e-310
0x80003c0000000000

Inputs, build details and evidence

How to implement

Use R(op) as defined in the stored arithmetic recipe.

  1. Coerce both arguments, reject a zero divisor, and return zero for a zero dividend. Compute q=R(number/divisor); reject abs(q)>=1.1259e12 or a nonfinite quotient.
  2. Compute the truncating binary64 remainder r, using a correctly implemented fmod primitive or integer significand/exponent reduction. Do not compute number-divisor*floor(q) in floating point: that can lose the small remainder.
  3. If r is nonzero and has the divisor’s opposite sign, normally set v=R(r+divisor). If that addition rounds exactly to the divisor, the current compatibility rule returns zero.
  4. Before that addition, a subnormal r of the opposite sign needs a special branch. With a=abs(divisor) and ordinary binary64 operations, set c=(2^27+1)*a, low=a-(c-(c-a)). A subnormal low, or abs(q)>=2^26, gives #NUM!. Otherwise, if abs(r)<2^-1026, return R(a+abs(r)) with the divisor’s sign. A larger remainder takes the normal addition.
  5. If no sign adjustment is needed, keep r. Any subnormal final result is #NUM!.

Worked ordinary path: fmod(-7,3)=-1; the signs differ, so -1+3=2. Worked large-quotient refusal: MOD(1125899999999,1) is recorded as zero, while MOD(1125900000000,1) is #NUM!.

To implement the truncating remainder without a host fmod, decode the positive magnitudes as Mx*2^Ex and My*2^Ey, with integer significands. Set E=min(Ex,Ey), A=Mx << (Ex-E) and B=My << (Ey-E). Take the integer remainder U=A mod B, then restore the dividend's sign to U*2^E. Arbitrary-size integers make the shifts and remainder exact. This is a separate calculation from the rounded quotient used by the rejection test; do not reuse that quotient to reconstruct the remainder.

For 10 and binary64 0.1, choose the common unit 2^-56. The integers are A=720575940379279360 and B=7205759403792794. Integer division gives quotient 99 and remainder 7205759403792754. Rescaling that remainder gives 0.09999999999999945. Rounding the quotient to 100 before subtracting would erase the answer this function records.

Worked tiny path: inputs -1.223247290044572e-296 and 1.223247290044539e-296 have an opposite-sign subnormal remainder. The recorded special branch adds its magnitude and returns 1.223247290044572e-296, larger than the divisor. The mathematically correct remainder is 1.2232472900445062e-296. The note retains input and result bits.

The rule matches the cited recorded bank and fresh probes. Interpreting the split as evidence of a Dekker product is an inference; the measured rule does not reveal Microsoft’s private implementation.

Rust code

Show the CalcFunc source of this function

Quoted from the public repository DnaCalc/DnaCalc, crates calc-func and calc-fml, at commit 9e1884369a67. Comments are the source's own. A kernel shared with other functions appears once, on its module page.

MOD · 1 lines · calc-func/src/catalogue/rounding.rs on GitHub
call(MOD, "MOD", 2, DIVISOR, modulo)
modulo · 46 lines · calc-func/src/catalogue/rounding.rs on GitHub
/// MOD: number - divisor * INT(number / divisor), with the sign of the divisor, as Excel computes
/// it (dc-j9k): the exact binary64 remainder of the number by the divisor (`%`, which rounds
/// nothing), plus the divisor once when the remainder's sign differs from the divisor's, an
/// addition at an arithmetic site. So MOD(10,0.1) is 0.09999999999999945 and MOD(-5.3,1) is
/// 0.7000000000000002, as Excel gives them (the catalogue oracle's sheet dcj9k_math: 124 of 124
/// readings). A zero divisor is #DIV/0!, and a quotient of magnitude 1.1259E+12 or more is #NUM!
/// (Excel: MOD(1125899999999,1) is 0 and MOD(1125900000000,1) is #NUM!). A remainder below the
/// normal range that needs the divisor added follows `tiny_remainder`.
fn modulo(
    arguments: &[CalcValue],
    services: &mut EvalServices<'_>,
) -> Result<CalcValue, FunctionFault> {
    numeric(MOD, arguments, services, |site, n| {
        let (number, divisor) = (n[0], n[1]);
        if divisor == 0.0 {
            return Err(Exit::Error(WorksheetErrorCode::Div0));
        }
        if number == 0.0 {
            return Ok(0.0);
        }
        let quotient = site.divide(number, divisor)?;
        if !(quotient.abs() < MOD_QUOTIENT_LIMIT) {
            return Err(Exit::Error(WorksheetErrorCode::Num));
        }
        let remainder = number % divisor;
        let result = if remainder != 0.0 && (remainder < 0.0) != (divisor < 0.0) {
            if remainder.is_subnormal()
                && let Some(result) = tiny_remainder(site, remainder, divisor, quotient)?
            {
                return Ok(result);
            }
            let adjusted = site.add(remainder, divisor)?;
            // A remainder the divisor absorbs is 0 (dc-bd5: MOD(-5,9.99999999999999E+307) is 0
            // in Excel 16.0.20430).
            if adjusted == divisor { 0.0 } else { adjusted }
        } else {
            remainder
        };
        // The recorded tiny MOD banks return #NUM! when the final remainder is subnormal.
        if result.is_subnormal() {
            Err(Exit::Error(WorksheetErrorCode::Num))
        } else {
            Ok(result)
        }
    })
}
tiny_remainder · 26 lines · calc-func/src/catalogue/rounding.rs on GitHub
/// A subnormal `remainder` whose sign differs from the `divisor`'s. A divisor whose Veltkamp low
/// part (the bits a split at 2^27 + 1 leaves below its high half) is itself subnormal gives #NUM!,
/// as does a quotient of 2^26 or more; the split's two parts are what a Dekker product of the
/// count and the divisor multiplies, and these are the cases where that product leaves the normal
/// range. Otherwise a remainder below 2^-1026 is added to the divisor's magnitude instead of taken
/// from it, and a larger one (`None`) takes the ordinary step. So MOD(-1.0000000000000001E-296,
/// 1E-296) is 1.0000000000000001E-296 and the same at 1E-300 is #NUM!, as Excel 16.0.20527 gives
/// them. This rule matches all 152,395 bank rows with normal operands and 1,128 new readings.
fn tiny_remainder(
    site: &Site<'_>,
    remainder: f64,
    divisor: f64,
    quotient: f64,
) -> Step<Option<f64>> {
    let magnitude = divisor.abs();
    let scaled = VELTKAMP_SPLIT * magnitude;
    let low = magnitude - (scaled - (scaled - magnitude));
    if low.is_subnormal() || quotient.abs() >= MOD_DEKKER_COUNT {
        return Err(Exit::Error(WorksheetErrorCode::Num));
    }
    if remainder.abs() >= SMALLEST_DISTANCE {
        return Ok(None);
    }
    let sum = site.add(magnitude, remainder.abs())?;
    Ok(Some(if divisor < 0.0 { -sum } else { sum }))
}

Kernels shared with other functions

Argument and result plumbing

No implementation has been published with a Handbook test suite for this function.

Version differences

The recorded environments below distinguish a reading from a same-input comparison. Counts describe captured inputs in each environment; overlapping captures and comparisons are not totals of unique worksheet calls.

Excel 16.0 buildPlatform and CPUCaptured inputs
19929Windows, bitness not recorded, CPU not recorded105
20430Windows, 64-bit, CPU not recorded152,432

The record contains no same-input comparison between these environments. Reading different inputs on different builds does not establish either a version change or cross-build agreement.

Recorded environments and comparison details.

Retained controls from the indexed captures:

Build and recorded CPUCaptured call or argumentsExcel result
19929, CPU not recorded=MOD(-32.02542717687437346,1.00000000000000000)0.9745728231256265 (0x3fef2fb3585ca380)
20430, CPU not recordedMOD(1,2)1 (0x3ff0000000000000)

These are earlier recorded answers, not new Excel runs or an additional cross-build comparison. The function JSON retains each source locator, exact argument bits where available, and input-route status. Call notation does not imply that captured binary64 values were entered as decimal formula literals.

Excel 16.0 build 20430

Windows 64-bit, CPU not recorded in this capture

MOD(-1.223247290044572e-296, 1.223247290044539e-296) returned 1.223247290044572e-296 (0x0280000000000079). MOD(1.223247290044539e-296, -1.2232472900445716e-296) returned #NUM!. Inputs were supplied through cells using Value2. These are controls from this environment, not a same-input comparison with another build.

Observed formulas and results
  • MOD(-1.223247290044572e-296, 1.223247290044539e-296) → 1.223247290044572e-296
    0x0280000000000079 (cell-value2)
  • MOD(1.223247290044539e-296, -1.2232472900445716e-296) → #NUM! (cell-value2)

Excel 16.0 build 19929

Windows, bitness not recorded, CPU not recorded

105 captured inputs are indexed for this environment. Capture dates are not recorded. This is a reading count, not a comparison with another build. Retained control =MOD(-32.02542717687437346,1.00000000000000000) returned 0.9745728231256265 (0x3fef2fb3585ca380). The selected archive row does not record its input plumbing; no input route is inferred.

Observed formulas and results
  • =MOD(-32.02542717687437346,1.00000000000000000) → 0.9745728231256265
    0x3fef2fb3585ca380 (not-recorded)

Excel 16.0 build 20430

Windows, 64-bit, CPU not recorded

152,432 captured inputs are indexed for this environment. Capture dates: 2026-09-29 to 2026-09-29. This is a reading count, not a comparison with another build. Retained control MOD(1,2) returned 1 (0x3ff0000000000000). The capture specifies exact-double bulk Value2 cell input.

Observed formulas and results
  • MOD(1,2) → 1
    0x3ff0000000000000 (cell-value2)

Alternatives

QUOTIENT truncates the quotient, so pairing it with MOD does not reconstruct mixed-sign inputs. INT supplies the floor convention; a language’s % may use another convention.

Named variants

No named variants are recorded yet.

Suggest a correction or contribute an implementation · For agents