Math and trigonometry functions
MMULT
Matches all 7 recorded answers
Recorded: 7 workbook cells. How we measure this · See the Rust code
Local names in 40 languages
| Language | Name in Excel |
|---|---|
| Arabic | MMULT |
| Bulgarian | MMULT |
| Czech | MMULT |
| Danish | MPRODUKT |
| German | MMULT |
| Greek | MMULT |
| English (Australia) | MMULT |
| English (United Kingdom) | MMULT |
| English (United States) | MMULT |
| Spanish | MMULT |
| Estonian | MMULT |
| Finnish | MKERRO |
| French | PRODUITMAT |
| Hebrew | MMULT |
| Croatian | MMULT |
| Hungarian | MSZORZAT |
| Indonesian | MMULT |
| Italian | MMULT |
| Japanese | MMULT |
| Korean | MMULT |
| Lithuanian | MMULT |
| Latvian | MMULT |
| Norwegian | MMULT |
| Dutch | PRODUCTMAT |
| Polish | MACIERZ.ILOCZYN |
| Portuguese (Brazil) | MMULT |
| Portuguese (Portugal) | MATRIZ.MULT |
| Romanian | MMULT |
| Russian | МУМНОЖ |
| Slovak | MMULT |
| Slovenian | MMULT |
| Serbian (Latin) | MMULT |
| Swedish | MMULT |
| Thai | MMULT |
| Turkish | DÇARP işlevi |
| Ukrainian | MMULT |
| Vietnamese | MMULT |
| Chinese (Simplified) | MMULT |
| Chinese (Hong Kong) | MMULT |
| Chinese (Traditional) | MMULT |
Names from Microsoft's support site.
What it does
MMULT(array1, array2)
MMULT(array1, array2) returns the matrix product of two matrices.
(AB)ᵢⱼ = Σₖ₌₁ⁿ aᵢₖ · bₖⱼ
Each entry of the result is a dot product: one row of the left matrix against one column of the right. Microsoft's page states the shape rule that makes this well defined:
"The number of columns in array1 must be the same as the number of rows in array2, and both arrays must contain only numbers."
So an m×n matrix times an n×p matrix gives an m×p result, and the shared dimension n — the length of every dot product — vanishes from the answer's shape.
Algebraic properties, all of which readers use and some of which surprise them:
- Associative: (AB)C = A(BC). Not commutative: AB ≠ BA in general, and the two products may not even have the same shape.
- Distributive over addition, and compatible with scalar multiplication.
- MUNIT is the identity: AI = IA = A at the matching size.
- det(AB) = det A · det B — the bridge to MDETERM, and the cheapest metamorphic test available for this family.
- (AB)ᵀ = BᵀAᵀ and (AB)⁻¹ = B⁻¹A⁻¹ — both reverse the order.
- Matrix multiplication is exactly function composition for the corresponding linear maps, which is why the order reverses and why it fails to commute.
Domain and range. Domain: any conformable pair of numeric matrices. Range: numeric matrices. The product is a polynomial in the entries — continuous, smooth, no poles, no branch cuts. As with MDETERM, every difficulty here is numerical rather than analytic; unlike MINVERSE, there is no singularity to approach.
Arguments
| Argument | Meaning | Required |
|---|---|---|
array1 | The left factor. | Yes |
array2 | The right factor. | Yes |
Both required; the declared arity is exactly two. Microsoft's page notes that both "can be given as cell ranges, array constants, or references".
Result shape and entry. MMULT returns an array with the row count of array1 and the column
count of array2. Microsoft's page gives the entry mechanics: in current Microsoft 365 the formula
spills from a single cell, and in earlier versions the output range must be selected first and the
formula confirmed with Ctrl+Shift+Enter.
Try it
Quirks
Result and edge cases
Returns Array of Number.
- A logical argument and numeric text both produce
#VALUE!, consistent with the documented "must contain only numbers" rule for text and undocumented for logicals — the same family-wide refusal noted on MDETERM. - An empty range produces
#VALUE!, matching the documented empty-cell rule. - Two inline 2×2 arrays produce the expected 2×2 product.
Errors
| Error | Documented condition |
|---|---|
#VALUE! | "Any cells are empty or contain text" |
#VALUE! | "The number of columns in array1 is different from the number of rows in array2" |
Error values inside either array propagate; the family declares a reduction error-collapse profile, so competing errors are folded rather than surfacing independently (coercion and lifting).
Microsoft's page documents no #NUM! for MMULT, and no overflow condition at all. Given that
a dot product of large entries overflows readily, that is a gap rather than a guarantee.
How to implement
Numerical notes
MMULT has no pivoting, no division, and no singularity. Every last bit it produces is decided by
one thing: the order in which the dot products accumulate.
The error bound
For a single dot product of length n computed by sequential accumulation, the standard bound (Higham, Accuracy and Stability of Numerical Algorithms, chapter 3) is
|fl(xᵀy) − xᵀy| ≤ γₙ · |x|ᵀ|y|, γₙ = n·u / (1 − n·u)
with u the unit roundoff. Two things follow immediately, and they are the whole practical story:
- The bound grows with n, the shared dimension — not with the size of the result. A product of two 2×500 and 500×2 matrices has four entries and five hundred terms each; it is a harder computation than a 20×20 by 20×20 product with four hundred entries.
- The bound is in terms of |x|ᵀ|y|, not |xᵀy|. When the terms of the dot product have mixed signs and largely cancel, the relative error in the answer is unbounded. This is the matrix version of catastrophic cancellation, and it is why differencing data before multiplying is dangerous.
Accumulation order changes the answer, and every implementation chooses one
Floating-point addition is not associative, so:
- Sequential left-to-right, pairwise, and blocked accumulation give different bits.
- A fused multiply-add contracts
a*b + cinto one rounding instead of two, changing the result — usually improving it, always changing it. - Cache-blocked and vectorised kernels reorder the sum by construction; a BLAS
dgemmand a naive triple loop will not agree to the last bit. - Strassen-style fast algorithms change the arithmetic entirely and have a different, weaker error bound — they are componentwise less stable, which is why they are rare in general-purpose libraries.
For a compatibility implementation the consequence is the same one recorded on
MINVERSE: matching another implementation's bits means matching its op
graph, not merely its algorithm. MMULT is the cleanest place in the family to see that,
because there is nothing else going on.
If you need accuracy rather than compatibility
The remedies are well established and none of them is reachable from the worksheet:
- Compensated (Kahan/Neumaier) summation, or the Dot2 algorithm of Ogita, Rump and Oishi ("Accurate sum and dot product", SIAM Journal on Scientific Computing 26(6), 2005), which delivers a result as accurate as one computed in twice the working precision, at a small constant multiple of the cost.
- Extended-precision accumulation of the dot product before rounding once at the end.
- Sorting or grouping terms by magnitude before summing, which helps in the mixed-sign case.
A natural-best implementation of MMULT should use a compensated dot product; an
excel-bitexact one must not, unless Excel does.
See implementation options for why those are different
deliverables.
Overflow
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.
MMULT · 6 lines · calc-func/src/catalogue/math.rs on GitHub51 mmult "MMULT" (2, 2) [R "array1", R "array2"] |s, a, sv| {
let left = matrix(s, a, 0, sv)?;
let right = matrix(s, a, 1, sv)?;
let product = k::matrix_family::mmult_kernel(&left, &right).map_err(Exit::Error)?;
out_matrix(s, &product)
}
mmult_kernel · 32 lines · calc-func/src/ported/matrix_family.rs on GitHubpub(crate) fn mmult_kernel(
left: &[Vec<f64>],
right: &[Vec<f64>],
) -> Result<Vec<Vec<f64>>, WorksheetErrorCode> {
if left.is_empty() || right.is_empty() {
return Err(WorksheetErrorCode::Value);
}
let left_cols = left.first().map_or(0, Vec::len);
let right_cols = right.first().map_or(0, Vec::len);
if left.iter().any(|row| row.len() != left_cols)
|| right.iter().any(|row| row.len() != right_cols)
{
return Err(WorksheetErrorCode::Value);
}
if left_cols != right.len() {
return Err(WorksheetErrorCode::Value);
}
let mut result = Vec::with_capacity(left.len());
for left_row in left {
let mut row = Vec::with_capacity(right_cols);
for col_idx in 0..right_cols {
let mut acc = 0.0;
for inner_idx in 0..left_cols {
acc += left_row[inner_idx] * right[inner_idx][col_idx];
}
row.push(acc);
}
result.push(row);
}
Ok(result)
}
Kernels shared with other functions
matrixcatalogue/math
Argument and result plumbing
failcatalogue/kitgridcatalogue/kitout_matrixcatalogue/kit
No implementation has been published with a Handbook test suite for this function.
Version differences
No comparison between specific Excel builds is recorded here yet. This does not establish that all builds behave alike.
Alternatives
Relationships
- MINVERSE —
MMULT(A, MINVERSE(A))against MUNIT is the residual test, and the most useful single thing to do with this family. Read the caution on theMINVERSEpage first: a small residual is not a certificate of an accurate inverse. - MDETERM — det(AB) = det A · det B is a metamorphic identity requiring no oracle and exercising two surfaces at once.
- MUNIT — the multiplicative identity;
MMULT(A, MUNIT(n))should return A unchanged, entry for entry, which is a strong exactness test because every dot product is a sum of exact zeros and one exact copy. SUMPRODUCT— the single-dot-product function.MMULTof a row by a column isSUMPRODUCT, and the two are worth comparing: if they accumulate in different orders they will differ in the last bits for the same data, which is a clean, oracle-free way to see accumulation order made visible.TRANSPOSE— the other shape operator, and the partner in (AB)ᵀ = BᵀAᵀ.LINESTand the regression family — they form and solve normal equations, which areMMULT(TRANSPOSE(X), X)in disguise. That product is famously the step that squares the condition number, which is why forming normal equations explicitly is discouraged.
Named variants
No named variants are recorded yet.
Suggest a correction or contribute an implementation · For agents