Financial functions

DB

Matches all 2,045 recorded answers

Recorded: 2,034 in the answer bank and 11 workbook cells. How we measure this · See the Rust code

Local names in 40 languages
LanguageName in Excel
Arabicقاعدة بيانات
BulgarianDB
CzechDB
DanishDB
GermanDB
GreekDB
English (Australia)DB
English (United Kingdom)DB
English (United States)DB
SpanishNOSQL
EstonianDB
FinnishDB
FrenchBase de données
HebrewDB
CroatianDB
HungarianKCS2
IndonesianDB
ItalianDB
JapaneseDB
KoreanDB
LithuanianDB
LatvianDB
NorwegianDB
DutchDB
PolishDB
Portuguese (Brazil)NoSQL
Portuguese (Portugal)DB
RomanianDB
RussianФУО
SlovakDB
SlovenianDB
Serbian (Latin)DB
SwedishDB
ThaiDB
TurkishDB
UkrainianDB
VietnameseDB
Chinese (Simplified)DB
Chinese (Hong Kong)DB
Chinese (Traditional)DB

Names from Microsoft's support site.

What it does

DB(cost, salvage, life, period, [month])

DB(cost, salvage, life, period, [month]) returns the depreciation charge for one period under the fixed-declining-balance method.

"Fixed" means the rate is fixed, not the charge: a constant fraction of the remaining book value is written off each period, so charges fall geometrically. Microsoft's Learn page states the whole schedule in three formulas.

The ordinary period:

charge = (cost − total depreciation from prior periods) × rate
where rate = 1 − (salvage / cost) ^ (1 / life),  rounded to three decimal places

The first period, prorated by the number of months the asset was held in the first year:

charge = cost × rate × month / 12

And the last period — the extra stub period that exists only when month < 12:

charge = ((cost − total depreciation from prior periods) × rate × (12 − month)) / 12

Those three formulas are quoted from Microsoft. Together they define a schedule of life periods when month is 12, and life + 1 periods otherwise: the first and last are partial years that sum to one full year of depreciation.

The derivation of rate is the idea worth pausing on. Solving salvage = cost × (1 − rate)^life for rate gives exactly the formula above: it is the constant rate that would depreciate the asset from cost down to precisely salvage over life periods. DB is therefore the declining-balance method that targets the salvage value, rather than one that stops when it reaches it.

Except that it does not quite reach it, because of the rounding.

Arguments

DB(cost, salvage, life, period, [month])

ArgumentMeaning (Microsoft's wording)Required?
cost"The initial cost of the asset."Required
salvage"The value at the end of the depreciation (sometimes called the salvage value of the asset)."Required
life"The number of periods over which the asset is being depreciated (sometimes called the useful life of the asset)."Required
period"The period for which you want to calculate the depreciation. Period must use the same units as life."Required
month"The number of months in the first year. If month is omitted, it is assumed to be 12."Optional, defaults to 12

period is 1-based. Period 1 is the first (possibly prorated) year. This is the opposite of AMORLINC and AMORDEGRC, which number depreciation periods from 0, and mixing the two conventions in one model is a reliable way to produce a plausible wrong schedule.

month is not a date. It is a count of months in the first year, so it prorates by twelfths regardless of the calendar. DB therefore needs no day-count basis and has none — which is exactly why it is not interchangeable with the French depreciation pair, which prorate by an actual date interval.

month < 12 adds a period. The schedule then runs to life + 1, with the last period taking the complementary (12 − month)/12 fraction. Asking for period = life + 1 with month = 12 is out of range; asking for it with month = 11 is the stub year.

salvage and cost enter only through their ratio, so scaling both by the same factor leaves rate unchanged and scales every charge linearly.

Numeric slots follow the shared model; see Coercion and lifting.

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.

Quirks

The rounded rate

rate is rounded to three decimal places before any charge is computed. Microsoft documents this explicitly, and it is not a display convention: the rounded rate is what the schedule uses, so it changes every number the function returns.

Two consequences follow, and both are visible in ordinary use:

  1. The schedule does not land on salvage. The exact rate would; a rate rounded to three decimals will not. A DB schedule summed over its whole life leaves a residual book value that is above or below salvage depending on which way the rounding went. Anyone reconciling a DB column against cost − salvage will find a discrepancy, and it is by construction.
  2. The function is a step function of its inputs. Nudge salvage, cost or life slightly and rate may not change at all — or may jump by 0.001, moving every subsequent charge. DB is therefore piecewise-constant in a way none of its siblings are, and small input errors produce either no error or a discontinuous one.

Result and edge cases

Returns a Number: the charge for the requested period, in the units of cost.

  • salvage = 0. The ratio is 0, 0^(1/life) is 0, and the rate is exactly 1 — so the first period writes off the entire asset (prorated by month) and later periods charge nothing. The formula is doing what it says; the method simply has no meaning when the target salvage is zero. Microsoft's page does not flag this. If Excel special-cases it, that is a divergence worth recording.
  • salvage close to cost gives a rate near 0, which rounds to 0.000 and produces a schedule of zeros. Again the rounding, not the mathematics.
  • period = life + 1 with month < 12 is the stub year and uses the last-period formula.
  • Fractional life is accepted; the "last full regular period" is taken as its floor, which moves where the stub-year formula applies.
  • Empty, missing and error arguments follow the shared call model; see The value universe.

Errors

Microsoft's Learn page documents no error conditions for this function — it carries the parameter table and the three formulas, and stops. There is no published statement of what happens with a negative cost, a month of 13, or a period beyond the schedule.

Note that salvage > cost is not rejected: the ratio exceeds 1, the power is above 1, and the rate goes negative — producing negative depreciation, that is, appreciation. Whether Excel admits that is unverified, and the documentation is silent.

How to implement

Numerical notes

  1. The rounding of rate dominates everything. Three decimal places is coarse: on a ten-period asset the difference between a rate of 0.2065 and its rounded 0.207 compounds through the whole schedule. Any implementation must round at exactly the same point — after forming 1 − ratio^(1/life), before the first charge — and with the same tie rule.
  2. ratio^(1/life) is a general power and is the only transcendental in the function. It is evaluated as exp(ln(ratio)/life) on most platforms, so DB inherits whatever pow the host provides — the same dependency the Handbook's research record traced through the bond and distribution families to a single shared library routine. The rounding to three decimals mercifully hides the last-bit differences, but only until the fourth decimal sits near a tie.
  3. The stub-year branch is decided by floor(life), so a fractional life moves it. This is an implementation decision with no documentary support.

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.

DB · 6 lines · calc-func/src/catalogue/financial.rs on GitHub
23 db_fn "DB" (4, 5) [V "cost", V "salvage", V "life", V "period", V "month"] |s, a, sv| {
    // W111 independent error-order controls: earlier required arguments precede month.
    let (cost, salvage, life, period) = (num(s, a, 0)?, num(s, a, 1)?, num(s, a, 2)?, num(s, a, 3)?);
    let month = if a.len() > 4 { num(s, a, 4)? } else { 12.0 };
    out(s, dep::db_kernel(cost, salvage, life, period, month))
}
round_to_3_places · 15 lines · calc-func/src/ported/depreciation_family.rs on GitHub
/// ROUND(x, 3), by the catalogue's ROUND rule: the exact decimal reading of `x`, rounded half away
/// from zero (OxFunc calls its round_fn::round_kernel here).
fn round_to_3_places(x: f64) -> f64 {
    use crate::decimal::{Direction, ExactDecimal};
    if x == 0.0 {
        return 0.0;
    }
    match ExactDecimal::read(x).round_at(-3, Direction::Nearest) {
        None => x,
        Some(rounded) => rounded
            .text()
            .parse()
            .expect("an exact decimal reads as a binary64"),
    }
}
db_rate · 46 lines · calc-func/src/ported/depreciation_family.rs on GitHub
fn db_rate(cost: f64, salvage: f64, life: f64) -> Result<f64, WorksheetErrorCode> {
    let ratio = crate::ported::excel_numeric::excel_x87_div(salvage, cost);
    // W111 ratio/power overflow and subnormal probes publish rate=1, rather
    // than propagating an intermediate numeric error. This is internal DB
    // arithmetic; the source Value2 inputs remain exactly as captured.
    let ratio = if !ratio.is_finite() || ratio.abs() < f64::MIN_POSITIVE {
        0.0
    } else {
        ratio
    };
    let exponent = crate::ported::excel_numeric::excel_x87_div(1.0, life);
    let integer_power = exponent.fract() == 0.0 && exponent < u32::MAX as f64;
    let power = if integer_power {
        // DB's integer dispatch is narrower than the worksheet POWER wrapper.
        let value = depreciation_integer_power(ratio, exponent as u32);
        if value.is_finite() {
            value
        } else {
            0.0
        }
    } else if ratio == 0.0 {
        0.0
    } else {
        // Above the unsigned-count sentinel, even exact integer exponents use
        // the positive power chain. Rate-half probes distinguish it from the
        // worksheet wrapper's wider repeated-multiplication integer branch.
        crate::ported::excel_numeric::excel_pow_positive(ratio, exponent)
    };
    // An overflowing exp/log product reaches NaN in the internal power chain.
    // DB publishes a zero rate on that route, distinct from an ordinary power
    // overflow/error or an underflowed finite power (W111 extreme-life probes).
    if power.is_nan() {
        return Ok(0.0);
    }
    if power.is_infinite() {
        return Err(WorksheetErrorCode::Num);
    }
    let power = if power.abs() < f64::MIN_POSITIVE {
        0.0
    } else {
        power
    };
    // DB uses Excel decimal ROUND, including its 15-significant-digit input
    // staging, not binary (rate*1000+0.5).floor()/1000.
    Ok(round_to_3_places(1.0 - power))
}
db_kernel · 71 lines · calc-func/src/ported/depreciation_family.rs on GitHub
pub fn db_kernel(
    cost: f64,
    salvage: f64,
    life: f64,
    period: f64,
    month: f64,
) -> Result<f64, WorksheetErrorCode> {
    validate_finite(&[cost, salvage, life, period, month])?;
    // The period and month are truncated, but life remains fractional. Original
    // positive periods below one still request the initial depreciation.
    let month = month.trunc();
    // The host first saturates a nonnegative count to u32, then interprets that
    // word as signed. W111 boundary probes distinguish this from an i32 cast:
    // 2^31 becomes MIN, while counts above u32::MAX become -1.
    let whole_period = (period as u32) as i32;
    let whole_life = (life as u32) as i32;
    if cost < 0.0
        || salvage < 0.0
        || life <= 0.0
        || period <= 0.0
        || month < 1.0
        || month > 12.0
        || i64::from(whole_period) > i64::from(whole_life) + if month < 12.0 { 1 } else { 0 }
    {
        return Err(WorksheetErrorCode::Num);
    }
    if cost == 0.0 {
        return Ok(0.0);
    }
    let rate = db_rate(cost, salvage, life)?;
    if rate == 0.0 {
        return Ok(0.0);
    }
    // These store boundaries are observed by W111 DB probes. Replacing the
    // book recurrence with cost minus a running total changes final bits.
    let mut dep = crate::ported::excel_numeric::excel_x87_mul(
        crate::ported::excel_numeric::excel_x87_mul(cost, rate),
        month / 12.0,
    );
    // Each depreciation amount is published before it changes the book.
    // A subnormal first/regular amount is zero even if subsequent negative-rate
    // growth could otherwise amplify that difference (W111 minimum-normal inputs).
    dep = publish_depreciation(dep)?;
    let mut book = crate::ported::excel_numeric::excel_x87_sub(cost, dep);
    let regular_periods = whole_period.min(whole_life).max(0) as usize;
    for p in 2..=regular_periods {
        dep = publish_depreciation(crate::ported::excel_numeric::excel_x87_mul(book, rate))?;
        if dep == 0.0 {
            break;
        }
        book = crate::ported::excel_numeric::excel_x87_sub(book, dep);
        if book == 0.0 {
            if p < regular_periods {
                dep = 0.0;
            }
            break;
        }
        if !book.is_finite() {
            return Err(WorksheetErrorCode::Num);
        }
    }
    if month < 12.0 && i64::from(whole_period) == i64::from(whole_life) + 1 {
        // The final partial year's quotient and rate product are separate
        // published amounts too: later multiplication must not recover a
        // subnormal intermediate (W111 minimum-normal final-year probes).
        let quotient = publish_depreciation(book / 12.0)?;
        let product = publish_depreciation(crate::ported::excel_numeric::excel_x87_mul(quotient, rate))?;
        dep = product * (12.0 - month);
    }
    publish_depreciation(dep)
}

Kernels shared with other functions

Argument and result plumbing

  • num catalogue/kit
  • out catalogue/kit

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
20430Windows, 64-bit, CPU not recorded129,326

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.

Excel 16.0 build 20430

Windows, 64-bit, CPU not recorded

129,326 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.

Alternatives

Relationships

  • DDB — the other declining-balance function. The contrast is sharp and worth learning: DDB takes the rate as a factor and derives nothing; DB derives the rate from the salvage ratio and rounds it. DDB clamps each charge so the book value never falls below salvage; DB has no clamp and relies on the rate to land near it. DDB has no first-year proration; DB has month.
  • VDB — the general declining-balance function, with a rate factor, a period range, and an optional switch to straight line. The most flexible member of the family.
  • SLN — straight line, (cost − salvage)/life, the flat comparison every declining-balance schedule is measured against.
  • SYD — sum-of-years-digits, an accelerated schedule that does exhaust cost − salvage exactly, unlike DB.
  • AMORDEGRC and AMORLINC — the French date-prorated pair. They answer the same accounting question with a date interval instead of a month count and with 0-based periods.
  • Confused with: DDB (above), and with the assumption that a DB schedule sums to cost − salvage. It does not.

Named variants

No named variants are recorded yet.

Suggest a correction or contribute an implementation · For agents