Engineering Lab · Numerical correctness

Understanding the original. Reconstructing the logic. Verifying the result.

A standalone COBOL expression evaluator rebuilt in Rust with explicit decimal arithmetic: 1,000 exact-decimal cases with zero failures, 2,000 of 2,000 legacy comparisons within a stated tolerance, and a 13-expression transcript that matches byte for byte.

Original workCOBCALC by Manny Juan · GPL-3.0-or-later, retained
Genyra repositoryGenyraLLC/cobcalc-rust
StatusVerified evaluator · Rust 1.1.0
Last verified2026-11-03· run passed
Upstream revisiond3d3d20d3021
Code reconstruction · COBCALC

The same grammar.
A different kind of number.

Left, the original's evaluation of a multiplication on its COMP-2 floating-point stack. Right, the Rust level that replaces it, where every result passes through a bounded decimal context.

Original · COBOLcobcalc.cob

03 EXP-RS COMP-2.
WHEN ('TERM3')
  PERFORM 1770-POP-OP
  EVALUATE (EXP-OP)
    WHEN ('*')
      PERFORM 1840-POP-RS
      MOVE EXP-RS TO EXP-WORK-RS-A
      PERFORM 1840-POP-RS
      MOVE EXP-RS TO EXP-WORK-RS-B
      COMPUTE EXP-RS = EXP-WORK-RS-B * EXP-WORK-RS-A
      PERFORM 1630-PUSH-RS

Operands are popped from a COMP-2 stack, which is binary floating point. Precedence lives in the mode transitions.

Reconstruction · Rustsrc/lib.rs

fn term(&mut self) -> Result<Number, Error> {
    let mut value = self.power()?;
    loop {
        if self.take(b'*') {
            let rhs = self.power()?;
            value = self.finite(value * rhs)?;
        } else if self.take(b'/') {
            let rhs = self.power()?;
            if rhs.is_zero() {
                return Err(self.error("division by zero"));
            }
            value = decimal_math::division(&value, &rhs)
                .map_err(|message| self.error(message))?;
        } else {
            return Ok(value);
        }
    }
}

Each grammar level is a function; every result passes through the bounded decimal context. Division by zero is an error with a column, not a NaN.

Execution flow · 2^3^2select a step

34 significant digits, half-even, with a 50-digit working context for the operations that cannot be exact. src/decimal_math.rs

Recorded demonstration · make demoREADME

ExpressionRust output
2+3*414.00000
(2+3)*420.00000
2^3^2512.00000
SQRT(144)+1,000/4262.00000
-2^24.00000
(5/1200*250000*((1+5/1200)^(30*12)))/(((1+5/1200)^(30*12))-1)1342.05405

Recorded from the published Rust binary in the original's five-place display. The last line is the original author's mortgage-payment example. 0.1+0.2 prints 0.3, where the original prints 0.29999: the one intentional difference, documented in MIGRATION.md.

1,000 Exact-decimal cases, zero failures Exact-decimal reference test
2000 of 2000 Legacy comparisons passing Tolerance-based numerical compatibility
642 Exact transcript lines Exact byte-for-byte comparison

01 / THE CASE

Why a calculator belongs in the Lab.

Precedence, right-associative powers, signed literals that bind before powers, commas inside integers, a square root, errors with a column number: COBCALC is small enough to read in an afternoon and complete enough to carry every question a numerical migration raises. Above all it carries the question of the number type, because the original keeps its result stack in COMP-2, which is binary floating point.

The Rust reconstruction keeps the grammar and changes the arithmetic deliberately: 34 significant digits, half-even, with a 50-digit working context for the operations that cannot be exact. 0.1 + 0.2 is 0.3.

02 / TWO STANDARDS

Two standards, never confused.

Because the original is floating point, agreement with it can only ever be agreement within a tolerance. So the Lab publishes two separate results. The exact-decimal contract: 1,000 deterministic cases compared as decimals with an independent reference, zero tolerance, zero failures. Legacy compatibility: 2,000 expressions run against the real GnuCOBOL original within an absolute and relative tolerance of 2e-12, 2,000 passing, largest observed difference about 1e-7. A selected 13-expression session additionally matches the original transcript byte for byte.

The second result is numerical compatibility. It is not a financial-equivalence claim, and the repository says so in its own verification file.

03 / BOUNDARY

The boundary of the claim.

An algebraic evaluator, not a banking, tax or payroll engine. Migrating such a system also requires each copybook's exact scale, receiving-field rounding policy, size-error behaviour and record encodings, and those must be verified separately and compared byte for byte. Choosing a decimal library proves none of them on its own.

Evidence explorer

Inspect the evidence.

Each view answers one question: what was shown, how, what Genyra built, the numbers, what has not been established, where the code is and how to run the same check yourself.

Understanding the original. Reconstructing the logic. Verifying the result.

A standalone COBOL algebraic expression evaluator rebuilt in Rust with explicit decimal arithmetic, and tested two ways: exactly against a decimal reference, and within a stated tolerance against the floating-point original.

1,000 Exact-decimal cases, zero failures Exact-decimal reference test
2000 of 2000 Legacy comparisons passing Tolerance-based numerical compatibility
642 Exact transcript lines Exact byte-for-byte comparison

Original work: Manny Juan, GPL-3.0-or-later, retained. Rust implementation and evidence: Genyra LLC. Status: Verified evaluator · Rust 1.1.0.

Techniques demonstrated
  • Expression parsing
  • Operator precedence
  • Source-language behaviour
  • Decimal arithmetic
  • Explicit precision
  • Rounding rules
  • Error handling
  • Equivalence testing
Before an enquiry

Questions we are asked.

Short answers in the same terms as the page. Anything specific to your systems is agreed by enquiry.

Why not make the Rust version match the COBOL output exactly?
Because the original's output is sometimes wrong in the way binary floating point is wrong: it displays 0.29999 for 0.1 + 0.2. Reproducing that would preserve an artefact rather than a rule. The reconstruction states a decimal contract instead, and measures its distance from the original honestly, within a published tolerance.
Is there a live calculator on this page?
No. The outputs shown are recorded from the published Rust binary and the verification transcripts. A browser calculator would have to implement the documented grammar and numeric rules faithfully to be worth showing; until it does, recorded demonstrations are the honest choice.
A CLEARER NEXT STEP

Discuss a reconstruction

From an unanswered question
to an engineered possibility.

Discuss a reconstruction
Chat on WhatsApp