Skip to content
PYD ENTERPRISES

Migration guide

COBOL to C# and .NET: precision, rounding and compiler options you have to carry over

C# decimal looks like a natural home for COBOL arithmetic, and mostly it is. This guide covers the places it is not, and the extraction workflow that hands a .NET team reviewed decision tables instead of paragraphs.

COBOLC# / .NET
DIFFICULTY
High
OUTPUT
DMN XML
SYNTAX TRAPS
5 covered
WORKFLOW
6 steps

By Pranav Kulkarni, Head of Language Engineering · Updated 15 Oct 2026

Technical syntax challenges

Where COBOL migrations go wrong.

01

Math.Round rounds to even by default

Math.Round(2.345m, 2) returns 2.34 because the default is MidpointRounding.ToEven. COBOL ROUNDED without a MODE phrase rounds half away from zero, giving 2.35. The spec records the rounding of every output so C# code passes MidpointRounding.AwayFromZero where COBOL said ROUNDED, and truncates where it did not.

02

Decimal has 28 to 29 significant digits

IBM Enterprise COBOL with ARITH(EXTEND) allows 31-digit fields and intermediate results. C# decimal holds 28 to 29 significant digits. Rare in business fields, but intermediate products of large balances and six-decimal rates can exceed it; the extractor flags computations whose declared precision does not fit.

03

TRUNC compiler option changes binary fields

PIC S9(4) COMP occupies a halfword, but under TRUNC(STD) values are truncated to four decimal digits (9999) while TRUNC(BIN) allows the full halfword range. The same source behaves differently by compile option, so PYD ENTERPRISES reads compile options from the build JCL or project settings.

04

Two-digit years and date windowing

ACCEPT WS-DATE FROM DATE returns YYMMDD, and Y2K remediation often added a sliding window such as 'below 50 means 20xx'. Those windows are business rules and must be explicit in the spec before anyone maps them to DateOnly.

05

Micro Focus dialect differences

Micro Focus COBOL adds COMP-5 native binary, different file handling options and directives set in project files. A distributed COBOL estate may compile the same copybook with different directives than the mainframe, which changes storage layout.

Extraction workflow

6 steps from source to signed-off spec.

The sequence a PYD ENTERPRISES Discovery Scan runs for this stack. Every output links back to source file and line range.

  1. 1

    Capture sources with compile options

    Export programs, copybooks and the compile JCL or Micro Focus project directives, so TRUNC, ARITH, NUMPROC and dialect settings are known per program.

  2. 2

    Parse and compute storage per option set

    PYD ENTERPRISES parses with the right dialect and computes storage layouts and value ranges under each program's compile options.

  3. 3

    Check precision against the target

    Every arithmetic expression is checked for intermediate precision against C# decimal limits, and risky computations are flagged with source lines.

  4. 4

    Extract decisions to DMN 1.5 XML

    Rating, pricing and eligibility logic becomes DMN 1.5 XML with FEEL expressions, importable into DMN-compliant engines and readable by analysts.

  5. 5

    Export contracts for .NET services

    Records become JSON Schema and candidate operations become OpenAPI 3.1 for ASP.NET Core teams, each element linked to its source.

  6. 6

    Run fixtures in the .NET test suite

    Boundary and rounding fixtures (including exact midpoints like x.xx5) are exported as JSON for xUnit or NUnit data-driven tests.

Legacy in, specification out

The source, and what PYD ENTERPRISES extracts from it.

Left: the COBOL construct as it sits in production. Right: the reviewed artifact your C# / .NET engineers build against. PYD ENTERPRISES produces the spec and the tests; your team writes the service.

LEGACY SOURCE

RATEAUTO.cbl (lines 812 to 829)COBOL
1 01 WS-AGE PIC 9(03).
2 01 WS-BASE-PREM PIC S9(7)V99 COMP-3.
3 01 WS-FACTOR PIC V9(4) COMP-3.
4 01 WS-PREMIUM PIC S9(7)V99 COMP-3.
5 01 WS-CLAIM-COUNT PIC S9(4) COMP.
6 *
7 4200-RATE-DRIVER.
8 EVALUATE TRUE
9 WHEN WS-AGE < 25
10 MOVE 1.4500 TO WS-FACTOR
11 WHEN WS-AGE < 70
12 MOVE 1.0000 TO WS-FACTOR
13 WHEN OTHER
14 MOVE 1.2000 TO WS-FACTOR
15 END-EVALUATE
16 IF WS-CLAIM-COUNT > 2
17 ADD 0.2500 TO WS-FACTOR
18 END-IF
19 COMPUTE WS-PREMIUM ROUNDED = WS-BASE-PREM * WS-FACTOR.

EXTRACTED ARTIFACT

RATE-DRV.dmnXML
1<definitions xmlns="https://www.omg.org/spec/DMN/20230324/MODEL/"
2 id="RATE-DRV" name="Driver rating"
3 namespace="https://pydenterprises.com/dmn/auto">
4 <decision id="ageFactor" name="Driver age factor">
5 <decisionTable hitPolicy="FIRST">
6 <input id="in1" label="Driver age">
7 <inputExpression typeRef="number"><text>driverAge</text></inputExpression>
8 </input>
9 <output id="out1" name="factor" typeRef="number"/>
10 <rule id="R1">
11 <inputEntry><text>&lt; 25</text></inputEntry>
12 <outputEntry><text>1.45</text></outputEntry>
13 </rule>
14 <rule id="R2">
15 <inputEntry><text>[25..70)</text></inputEntry>
16 <outputEntry><text>1.00</text></outputEntry>
17 </rule>
18 <rule id="R3">
19 <inputEntry><text>&gt;= 70</text></inputEntry>
20 <outputEntry><text>1.20</text></outputEntry>
21 </rule>
22 </decisionTable>
23 </decision>
24 <!-- source RATEAUTO.cbl:819-826; claim surcharge +0.25 when
25 claimCount > 2 is decision claimLoad; premium ROUNDED half-up -->
26</definitions>

Architectural best practices

Build the C# / .NET side to the spec, not to the old shape.

  • Use MidpointRounding.AwayFromZero wherever the COBOL statement says ROUNDED, and explicit truncation where it does not.
  • Record compile options with every extracted rule; the same COBOL source is not the same behavior under different TRUNC settings.
  • Keep rating tables in DMN and call them from .NET, or implement them in C# under fixture tests, but keep one source of truth.
  • Make date windowing an explicit, named rule with an owner and an expiry, not a helper method.
  • Include exact midpoint values in every rounding fixture set; they are the cases that differ between ToEven and AwayFromZero.

Why C# teams still need the spec

Microsoft-centric organizations often choose .NET for the target because the team and the operations tooling are already there. Some also have Micro Focus or similar COBOL running on Windows or Linux, which makes a gradual move attractive. In both cases the risk is the same as any rewrite: behavior nobody wrote down.

PYD ENTERPRISES extracts that behavior as DMN decisions, JSON Schema and OpenAPI contracts, and fixtures, each tied to source lines and compile options, and your analysts sign off before development starts. PYD ENTERPRISES does not translate COBOL to C# and does not write the .NET services.

A rounding example worth testing

Base premium 1,234.50 with a factor of 1.4500 gives 1,790.025. COBOL ROUNDED stores 1,790.03. Math.Round(1790.025m, 2) in C# returns 1,790.02. Across a book of policies, that one-cent difference shows up in reconciliation, in regulatory filings and in customer complaints. The generated fixtures include exactly this kind of midpoint case for every rounded output, because they are the ones a unit test written from intuition rarely covers.

FAQ

COBOL to C# / .NET questions

Does PYD ENTERPRISES support Micro Focus COBOL as well as IBM Enterprise COBOL?

Yes. Both dialects are supported, along with their compiler directives. Specify the dialect per source set so storage layouts and arithmetic match the compiler that builds each program.

Can the DMN output run in .NET?

The DMN 1.5 XML is engine neutral. Teams either host a DMN engine as a decision service called from .NET, or implement the tables in C# and use the exported fixtures to prove the implementation matches.

Is the rounding mode detected automatically?

Yes. ROUNDED, ROUNDED MODE phrases and truncation are recorded per statement, and every output in the spec states its rounding.

Get the spec for your COBOL estate.

Request a codebase scan and review extracted rules, contracts and fixtures for your own COBOL estate, inside your VPC.