Cost rollup formulas losing decimal precision when aggregating component costs across BOM levels

We’re encountering precision loss in cost rollup calculations in TC 12.3 that’s causing significant discrepancies in our product costing. When the formula engine aggregates component costs up through multi-level BOMs, we’re losing 2-3 decimal places, which compounds at each level.

For example, a component with actual cost $0.00347 gets rounded to $0.003 at level 2, then $0.00 at level 3. When you multiply by quantities (we have fasteners used 200+ times per assembly), the errors accumulate to $50-100 per product, which is unacceptable for pricing accuracy.

double totalCost = 0.0;
for (Component comp : bomComponents) {
    totalCost += comp.getUnitCost() * comp.getQuantity();
}
// Precision lost in floating-point arithmetic

I suspect the issue is in how the formula-mgmt module handles decimal precision during aggregation, and possibly the order in which calculations are performed. Has anyone configured proper rounding strategies and decimal precision settings for cost formulas?

Your precision loss requires coordinated fixes across decimal configuration, aggregation queries, rounding strategy, and calculation order.

Decimal Precision Configuration: First, update database schema to support 6 decimal places:

ALTER TABLE CostData
MODIFY COLUMN unitCost DECIMAL(14,6),
MODIFY COLUMN extendedCost DECIMAL(16,6);

Use DECIMAL(14,6) for unit costs (supports values up to $99,999,999.999999) and DECIMAL(16,6) for extended costs to handle large quantities.

In formula-mgmt configuration, set precision attributes:

<costFormula id="BOM_ROLLUP" precision="6"
             roundingMode="HALF_UP" roundAt="FINAL" />

The roundAt=“FINAL” is critical - maintain full precision through intermediate calculations, round only when presenting final product cost.

Aggregation Query Optimization: Rewrite aggregation using BigDecimal:

BigDecimal totalCost = BigDecimal.ZERO;
for (Component comp : bomComponents) {
    BigDecimal unitCost = new BigDecimal(comp.getUnitCost())
        .setScale(6, RoundingMode.HALF_UP);
    BigDecimal quantity = new BigDecimal(comp.getQuantity());
    totalCost = totalCost.add(unitCost.multiply(quantity));
}
return totalCost.setScale(2, RoundingMode.HALF_UP); // Round at final step only

Never use double arithmetic for currency. The statement double totalCost = 0.0 guarantees precision loss. BigDecimal maintains exact decimal representation.

Rounding Strategy: Implement a three-tier rounding strategy:

  1. Component level: Store at 6 decimals, no rounding
  2. Assembly level: Calculate at 6 decimals, display at 4
  3. Product level: Calculate at 6 decimals, round to 2 for pricing

Use HALF_UP rounding (banker’s rounding) consistently. Configure in site.xconf:


formula.cost.internalPrecision=6
formula.cost.displayPrecision=2
formula.cost.roundingMode=HALF_UP

Formula Calculation Order: Implement bottom-up rollup with proper sequencing:

// Pseudocode - Correct calculation sequence:
1. Start at leaf components (no child BOMs)
2. For each leaf: extendedCost = unitCost * quantity (6 decimals)
3. Move up one level, aggregate all child costs
4. Add assembly-level costs (labor, overhead)
5. Repeat until reaching top-level product
6. Apply final rounding only at product level

The order matters because:

  • Quantity * UnitCost * Overhead ≠ (Quantity * UnitCost) + (Quantity * Overhead) due to rounding
  • Calculating leaf-to-root ensures each multiplication happens once
  • Summing before multiplying amplifies rounding errors

For your fastener example ($0.00347 × 200 qty):

  • Wrong: $0.003 × 200 = $0.60 (rounded too early, $0.094 error)
  • Right: $0.00347 × 200 = $0.694 (round to $0.69 at final step)

Implement validation: recalculate 10 products manually in Excel with 6 decimal precision, compare to TC results. Variance should be <$0.01 per product. If larger, trace which formula step introduces error.

After schema changes, run data migration:

UPDATE CostData SET unitCost =
  CAST(sourceUnitCost AS DECIMAL(14,6))
WHERE precision < 6;

This comprehensive fix eliminates precision loss and ensures your cost rollups are accurate for pricing decisions.

I checked the database schema and found the issue - cost columns are DECIMAL(12,2). That explains the truncation. If I change to DECIMAL(12,6), will existing cost data be preserved or do I need to migrate? Also, for the BigDecimal approach, does TC’s formula engine natively support that or do I need custom code?

The calculation order matters too. If you’re doing quantity * unitCost at each level then summing, you get different results than summing unitCosts first then multiplying. For nested BOMs, always calculate from leaf nodes upward and maintain precision throughout. We implemented a bottom-up rollup strategy that reduced our variance from 4% to under 0.1%.

Changing column precision is safe - existing values will be preserved and just get more decimal places (padded with zeros). But you’ll need to update all existing cost records to recalculate with full precision. Run a batch update job to recompute costs from source data. Don’t just keep the rounded values with extra zeros.

Beyond the BigDecimal fix, you need to configure precision at the formula level. In formula-mgmt, there’s a precision attribute you can set per cost formula. We use 6 decimal places for component costs and round only at the final product level. Also check your database column definitions - if they’re defined as DECIMAL(10,2), you’re truncating at the database level before TC even sees the full precision.