Excel 16.0 build 20131
Windows, bitness not recorded, AMD Ryzen 7 4800H with Radeon Graphics
12 captured inputs are indexed for this environment. Capture dates: 2026-07-12 to 2026-07-12. This is a reading count, not a comparison with another build.
Statistical functions
Close: 2 of 211 recorded answers differ in the last bits, worst 2 ULP
Everything else matches (12 in the answer bank and 199 workbook cells). Last-bit means a finite number within 16 ULP of Excel's. How we measure this · See the Rust code
| Language | Name in Excel |
|---|---|
| Arabic | TREND |
| Bulgarian | TREND |
| Czech | TREND |
| Danish | TENDENS |
| German | TREND |
| Greek | TREND |
| English (Australia) | TREND |
| English (United Kingdom) | TREND |
| English (United States) | TREND |
| Spanish | TENDENCIA |
| Estonian | TREND |
| Finnish | TRENDI |
| French | TENDANCE |
| Hebrew | TREND |
| Croatian | TREND |
| Hungarian | TREND |
| Indonesian | TREND |
| Italian | TREND |
| Japanese | TREND |
| Korean | TREND |
| Lithuanian | TREND |
| Latvian | TREND |
| Norwegian | TREND |
| Dutch | TREND |
| Polish | REGLINW |
| Portuguese (Brazil) | TENDÊNCIA |
| Portuguese (Portugal) | TENDÊNCIA |
| Romanian | TREND |
| Russian | ТЕНДЕНЦИЯ |
| Slovak | TREND |
| Slovenian | TREND |
| Serbian (Latin) | TREND |
| Swedish | TREND |
| Thai | TREND |
| Turkish | EĞİLİM |
| Ukrainian | TREND |
| Vietnamese | TREND |
| Chinese (Simplified) | TREND |
| Chinese (Hong Kong) | 趨勢 |
| Chinese (Traditional) | 趨勢 |
Names from Microsoft's support site.
TREND(known_ys, [known_xs], [new_xs], [const])
TREND(known_y's, [known_x's], [new_x's], [const]) fits a linear model to the known data by the
method of least squares — Microsoft's page says so in those words — and returns the fitted
values of that model at the new x positions.
With one predictor the model is the familiar y = m·x + b that the documentation names. With
several predictors it is
y = m₁x₁ + m₂x₂ + … + m_kx_k + b
and TREND returns ŷ* = X* β̂ where β̂ minimizes ‖y − Xβ‖₂ over the known data. In matrix
terms, with X the n × (k+1) design matrix whose first column is all ones (when const is
TRUE or omitted):
β̂ = argmin ‖y − Xβ‖₂ ⟺ XᵀX β̂ = Xᵀy (the normal equations)
The normal-equations characterization is mathematically correct and numerically the worst way
to obtain β̂; that distinction is the entire subject of the Numerical notes section, and it is
the subject of the evidence record attached to this page.
For the single-predictor case the solution is explicit:
b_slope = Sxy / Sxx, b_intercept = ȳ − b_slope·x̄
with Sxx = Σ(x − x̄)² and Sxy = Σ(x − x̄)(y − ȳ). Two things follow that matter more than
they look:
Sxx written as
Σ(x − x̄)² and Sxx written as Σx² − (Σx)²/n are the same real number and wildly
different floating-point numbers when the data has a large mean relative to its spread.const = FALSE removes the option to centre. With the intercept forced to zero the model
is y = m·x and the estimator is Σxy / Σx² — an uncentred quantity by necessity. The two
settings of const are therefore not one algorithm with a flag; they are two.TREND is a dynamic array surface: it returns one fitted value per row of new_x's, so its
result is generally an array rather than a scalar.
| Argument | Meaning | Default when omitted |
|---|---|---|
known_y's | "The set of y-values you already know in the relationship y = mx + b". Required. | — |
known_x's | "An optional set of x-values you may already know". | {1, 2, 3, …} the same size as known_y's |
new_x's | "New x-values for which you want TREND to return corresponding y-values". | the same as known_x's |
const | Logical: whether to force the constant b to zero. | TRUE — b is calculated normally |
Documented details worth stating precisely, because each one is a place readers get surprised:
known_x's substitutes the index sequence {1,2,3,…}. TREND(A1:A12) is a
regression against time-as-row-number, and it is a real model, not a degenerate one.new_x's re-uses known_x's, which makes TREND(y, x) the vector of fitted
values — the in-sample predictions — rather than a forecast.const = FALSE sets b = 0 and adjusts the m values so that y = mx. It does not
simply drop the intercept from a fit computed with one; the whole fit changes.known_y's must be a
vector.x, x², x³ as separate predictor columns. This is worth
flagging as the numerically hardest thing TREND is documented to do — the Vandermonde design
matrix it produces is the standard example of an ill-conditioned least-squares problem.Returns Number values, generally as an array shaped by new_x's.
new_x's, which is one of the two most common sources of #REF! and #VALUE!
from this function; the other is a design matrix whose predictor columns run the wrong way.XᵀX singular. What Excel does then is not
documented on this page.x values sit far from zero relative to their spread (times as
serial dates, sensor readings around a large baseline) is the regime where the uncentred and
centred arrangements of the same formula give visibly different answers. It is also the regime
the evidence record attached to this page found most diagnostic.BUG-FUNC-028, whose title names an
unswept conversion, text/date, array-lift and coercion gap; the Handbook cites it by name and
does not restate its contents.Microsoft's TREND page carries no error table. That is itself a finding: a function with a
documented rank-deficiency exposure, a documented orientation requirement, and a documented
optional-argument default chain publishes no documented error conditions at all.
What can be said honestly:
Nothing in this table is a documented Microsoft statement, and the Handbook has not verified any of it against Excel.
Least squares is the best-studied problem in numerical linear algebra, and the whole literature
converges on one sentence: do not form XᵀX.
Why. The normal equations square the condition number: κ₂(XᵀX) = κ₂(X)². A design matrix
with a modest condition number of 10⁶ — easily produced by a quadratic fit on data that does not
straddle zero — yields a normal-equations system with condition number 10¹², and in double
precision that consumes most of the available accuracy before the solve begins. A Vandermonde
matrix from a cubic or higher polynomial fit is far worse; this is why the NIST StRD Filip
dataset (a tenth-degree polynomial fit) is the standard executioner of regression
implementations.
The alternatives. A Householder QR factorization X = QR reduces the problem to the
triangular system Rβ̂ = Qᵀy and works with κ₂(X), not its square; a singular value
decomposition additionally handles rank deficiency gracefully and yields the minimum-norm
solution. These are the recommendations of Lawson & Hanson, Björck, Golub & Van Loan, and
Higham's Accuracy and Stability of Numerical Algorithms chapter 20, and they are what LAPACK's
gels/gelsd do. Solving normal equations with a Gauss–Jordan inverse — forming (XᵀX)⁻¹
explicitly and multiplying — is the worst option available on both accuracy and stability
grounds, and it is the one textbooks use to state the model.
Centring. For a model with an intercept, subtracting the column means before the solve and
recovering b = ȳ − Σ mⱼx̄ⱼ afterwards is mathematically equivalent and numerically decisive: it
removes the offset that otherwise dominates every entry of XᵀX. With const = FALSE this route
is closed, because there is no intercept to absorb the shift — which is exactly why the two
const settings deserve separate treatment and separate testing.
FORECAST, generalized to the
design matrix — does substantially better on the same witnesses. Its score is a candidate
score, not the shipping surface's; the record's reader warning says so, and this page repeats
it.ruled_out list is the interesting part, because each entry is a conclusion about
Excel, reached by elimination: any one-pass computational sum-of-squares formula is
refuted, because it explodes on the huge-offset dataset where Excel does not — so Excel
centres. Extended-precision-throughout arrangements are refuted as strictly worse. And every
natural centred variant raced — forward and reverse accumulation, extended precision, centred
QR by Householder, centred normal equations, fused-multiply-add dot products, symmetric versus
asymmetric centring, one- versus two-pass — reproduces FORECAST's slope and never TREND's.TREND's slope on the residual datasets is under-determined by the available witnesses,
and the multivariate regime is entirely unprobed.The figures behind all of that belong to the evidence layer rendered beside this page and are not restated in this prose. The record also carries a warning this page must repeat in its own voice: the catalogue's observation that the prediction step reproduces Excel given the coefficients is a decomposition of the problem, not a pass rate, and it must never be read as "TREND matches Excel".
The accuracy of Excel's regression outputs is also the subject of a published literature — Morten Welinder's work on Gnumeric's statistical functions, and the NIST StRD assessments by Knüsel and by McCullough & Wilson. The Handbook names those as the right reading and does not assert from them what any current Excel build does.
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.
TREND · 3 lines · calc-func/src/catalogue/statistics.rs on GitHub55 trend "TREND" (1, 4) [R "known_ys", R "known_xs", R "new_xs", V "const"] |s, a, sv| {
regression(s, a, sv, k::regression_forecast_family::eval_trend_surface, RegressionNumbers::Standard)
}
linear_model_from_data · 7 lines · calc-func/src/ported/regression_forecast_family.rs on GitHubfn linear_model_from_data(
known_y: &NumericVector,
known_x: &PreparedPredictorInput,
use_const: bool,
) -> Result<LinearRegressionModel, WorksheetErrorCode> {
linear_fit_from_data(known_y, known_x, use_const).map(|fit| fit.model)
}
linear_prediction · 6 lines · calc-func/src/ported/regression_forecast_family.rs on GitHub/// A TREND prediction: `b_1*x_1 + b_2*x_2 + ...`, added in predictor order, then the intercept.
fn linear_prediction(model: &LinearRegressionModel, x: &[f64]) -> f64 {
let mut terms = model.coefficients.iter().zip(x.iter()).map(|(b, x)| b * x);
let first = terms.next().unwrap_or(0.0);
terms.fold(first, |sum, term| sum + term) + model.intercept
}
trend_kernel · 15 lines · calc-func/src/ported/regression_forecast_family.rs on GitHubfn trend_kernel(
known_y: &NumericVector,
known_x: &PreparedPredictorInput,
new_x: &PreparedPredictorInput,
use_const: bool,
) -> Result<CalcValue, WorksheetErrorCode> {
let model = linear_model_from_data(known_y, known_x, use_const)?;
if new_x.predictors.cols != model.coefficients.len() {
return Err(WorksheetErrorCode::Ref);
}
let predicted = (0..new_x.predictors.rows)
.map(|row_idx| linear_prediction(&model, new_x.predictors.row_values(row_idx)))
.collect::<Vec<_>>();
eval_value_from_output_shape(&predicted, new_x.output_shape)
}
eval_trend_surface · 20 lines · calc-func/src/ported/regression_forecast_family.rs on GitHubpub(crate) fn eval_trend_surface(
args: &[CalcValue]
) -> Result<CalcValue, WorksheetErrorCode> {
let known_y = collect_numeric_vector_arg(&args[0])?;
let known_x_raw = args
.get(1)
.filter(|arg| !matches!(arg.core_ref(), CoreRef::Missing))
.map(|arg| collect_numeric_matrix_arg(arg))
.transpose()?;
let known_x = predictor_input_from_optional(known_x_raw, &known_y)?;
let new_x_raw = args
.get(2)
.filter(|arg| !matches!(arg.core_ref(), CoreRef::Missing))
.map(|arg| collect_numeric_matrix_arg(arg))
.transpose()?;
let new_x = prediction_input_from_optional(new_x_raw, &known_y, &known_x)?;
let use_const =
bool_flag_from_eval_or_default(optional_arg_value(args.get(3))?, true)?;
trend_kernel(&known_y, &known_x, &new_x, use_const)
}
regression catalogue/statisticsbinary_with ported/excel_numericexcel_x87_add ported/excel_numericexcel_x87_sub ported/excel_numericexcel_x87_mul ported/excel_numericexcel_x87_div ported/excel_numericmul ported/excel_numeric/x87add ported/excel_numeric/x87sub ported/excel_numeric/x87div ported/excel_numeric/x87GramInterval::checked ported/regression_forecast_familyGramInterval::subtract ported/regression_forecast_familyGramInterval::multiply ported/regression_forecast_familyGramInterval::square ported/regression_forecast_familyGramInterval::divide_positive ported/regression_forecast_familymoment ported/regression_forecast_familycolumn ported/regression_forecast_familyentry ported/regression_forecast_familyfactor_column ported/regression_forecast_familyunresolved_inner ported/regression_forecast_familyunresolved ported/regression_forecast_familyresolve_arg_eval ported/regression_forecast_familyoptional_arg_value ported/regression_forecast_familynumeric_from_cell ported/regression_forecast_familynumeric_scalar_from_eval ported/regression_forecast_familybool_flag_from_eval_or_default ported/regression_forecast_familycollect_numeric_vector_from_eval ported/regression_forecast_familycollect_numeric_vector_arg ported/regression_forecast_familyNumericMatrix::cell ported/regression_forecast_familyNumericMatrix::transpose ported/regression_forecast_familyNumericMatrix::row_values ported/regression_forecast_familycollect_numeric_matrix_from_eval ported/regression_forecast_familycollect_numeric_matrix_arg ported/regression_forecast_familysequence_predictors ported/regression_forecast_familydefault_output_shape_for_known_y ported/regression_forecast_familynormalize_known_x_matrix ported/regression_forecast_familyprepare_predictor_input ported/regression_forecast_familypredictor_input_from_optional ported/regression_forecast_familyprediction_input_from_optional ported/regression_forecast_familyleast_squares ported/regression_forecast_familyexact_product ported/regression_forecast_familyexactly_proportional ported/regression_forecast_familylinear_fit_from_data ported/regression_forecast_familyeval_value_from_output_shape ported/regression_forecast_familygrid catalogue/kitout_with_subnormal catalogue/kitNo implementation has been published with a Handbook test suite for this function.
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 build | Platform and CPU | Captured inputs |
|---|---|---|
| 20131 | Windows, bitness not recorded, AMD Ryzen 7 4800H with Radeon Graphics | 12 |
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.
Windows, bitness not recorded, AMD Ryzen 7 4800H with Radeon Graphics
12 captured inputs are indexed for this environment. Capture dates: 2026-07-12 to 2026-07-12. This is a reading count, not a comparison with another build.
FORECAST / FORECAST.LINEAR are the single-predictor, single-point special case. This
relationship is not decorative: the record attached to this page found that every natural
centred arrangement it raced reproduced FORECAST's slope and never TREND's, on the datasets
where the two disagree. Two Excel surfaces that ought to compute the same slope apparently do
not compute it the same way — and that is a finding about Excel's internals, arrived at by
elimination.GROWTH is TREND on ln y: the exponential model y = b·m^x, fitted by least squares in
the log domain. Same module, same machinery, different link.SLOPE, INTERCEPT, RSQ, STEYX are the scalar readouts of the same single-predictor
fit; STEYX tabulates the correspondence.FORECAST.ETS (exponential smoothing, an entirely different model),
charting trendlines (which fit the same model but display coefficients rounded for the label),
and SLOPE×x + INTERCEPT written out by hand, which is a third route to the same number
and need not agree with either of the first two in the last bits.No named variants are recorded yet.
Suggest a correction or contribute an implementation · For agents