cint is a C family language in which every number is an integer and every plain operator is checked. There is no float, no double, and no silent wrap. When an operation cannot produce the exact result the program stops and writes a fault record that names the operation, the operands, the exact value that was wanted and the limit that stood in its way. That is the whole idea, and everything else on this site follows from it: the two compilers that have to agree byte for byte, the C that one of them emits, the receipts that say the same bytes came out of four toolchains on two architectures, and the papers that put the idea to work.
On 4 June 1996 the first Ariane 5 left Kourou and about 30 seconds later it tore itself apart, and the inquiry board found the cause in a single conversion inside the inertial reference system. A 64-bit floating-point horizontal velocity term was packed into a 16-bit signed integer by code carried over from Ariane 4, which had never flown fast enough for the value to exceed 16 bits. Ariane 5 did. The conversion overflowed, the exception had no handler because the analysis had judged it impossible, and the unit shut itself down; its backup, running the same software on the same trajectory, had already shut down for the same reason. The four Cluster satellites in the fairing were lost. The arithmetic was not wrong, the value really was larger than 32,767; what was missing was a check at the one place the width changed.
On 23 September 1999 the Mars Climate Orbiter passed behind Mars and did not come out, and the review board traced the loss to a file of small thruster firings that one team produced in pound-force seconds and the other read as newton seconds, as the interface specification said it should be. Every correction over nine months was off by the factor 4.45 between the two units, and the spacecraft arrived about 57 kilometers above the surface instead of the planned 226, below the height it could survive. Two engineering cultures in one country had agreed a standard on paper and one of them had not followed it in code. Nothing in either program could tell, because a number in a file carries no unit, and a floating-point multiply is just as happy to be wrong by 4.45 as it is to be right.
cint takes a narrow lesson from each. From the first, that a change of width is an operation and gets checked like any other. That is narrowing.ci, where the same conversion faults at the first value that does not fit. From the second, that cint does not know what a newton is and does not pretend to. What it gives you is that a conversion between scales is a line you can see, written with the exact factor and a named rounding, which is units.ci. Neither program would have saved either mission by itself. Both make the place where the mistake lives visible.
Run hello_overflow and read the right-hand box. outcome fault says the program stopped. fault.code E_OVERFLOW says why, and there are thirteen such codes, for overflow, narrowing, division by zero, a bad index, a bad slice, a domain error, and the rest. fault.operation add.checked.i64 names the operation that could not complete. The name is the same in the reference, in the compiler, in the emitted C and in the specification, so there is never a question of which addition. The two fault.operand lines carry the inputs. fault.exact is the result the operation wanted to give, computed without limit, and fault.limit is the bound of the type it had to fit into. A reader sees at once by how much the value missed. fault.position is the line and column in the source. Everything the program wrote before the fault stays in stdout, and the record is the same bytes every time, on every machine, which is what lets it be compared and hashed.
hello_overflow.ci Run the first Run loads Python, about 12 MB, once
The integer types are I8 to I64 and U8 to U64, with I128 and wider available in the reference, and the names are capitalised because every name of the form I, U, Q or T followed by digits, such as T1, Q3, I2 or U8, is reserved for a type whether or not that type exists yet, so that a type added later can never collide with a name already in a program. Declaring a variable named Q3 is compile error C1010 though there is no Q3 type. I64 is a type and i64 is compile error C3006, an unknown type. Nothing widens by itself: an I32 added to an I64 is an error, not a promotion, and the conversion you write with as is checked, which is the Ariane case above. The plain operators are checked. When you really do want a result that stays in range there are two spellings that say so out loud, +| for saturating, which is overflow_hunt saturated, and +% for wrapping, which is overflow_hunt wrapped, so a reader of the source can tell the three apart at a glance. Division is floor division, and the operations that need a rounding rule take it by name. muldiv(I64, a, b, c, half_even) computes a * b / c with the product kept wide and one rounding at the end, which is how money without floats charges tax; div_round and isqrt work the same way. Literals take underscores, 1_000_000, and a literal that does not fit its type is rejected before the program runs.
A file of statements is a script and runs top to bottom, which is what the examples are. A file with void main() is a program, and a file with neither is a module for other files to import, which cint run refuses to run because it has nothing to do. Functions declare their result type first and their parameters cannot be reassigned. Structs are plain records built by calling the type name, and a test "name" { } block sits beside the code it tests and runs under cint test, with assert(...) taking parentheses, all of which is structs and tests in twenty lines. Strings are written with braces for interpolation and a string statement on its own line prints, so "total {x}\n"; is the whole of output.
An array is owned storage and a[lo..hi] is a view into it, declared with in for read-only or inout for writable, and a view copies nothing and carries its own bounds, so an index outside it is E_BOUNDS with the index and the extent in the record rather than a read of whatever lay next in memory. slices without copies shows it in the reference. The compiler accepts part of this surface today and not all of it, which the next paper takes up.
There are two implementations and they are not allowed to disagree. cint_ref is the reference, about nine thousand lines of Python, and it is what runs in this page: slow, readable, and the reference that the compiler is compared against. cintc is the compiler, written in cint itself. It emits C17 that is built with the small runtime that does the checking, and the lower box on this page shows what it emitted for the program as shipped. Every conformance case in the suite is run through both and the outputs are compared byte for byte, stdout and the fault record alike. At the gate of 2026-10-05 that was 472 programs and 1,839,155 records compared with no disagreement, with the cases the compiler does not yet accept published beside them under their own names rather than quietly skipped. same bytes everywhere is the small version of that promise. The compiler also catches what it can before the program runs: in caught twice both operands of a multiply are literals, so it folds them and refuses the program, and in the variant one operand is hidden in a variable, so the runtime catches it instead, with the same record.
cintc compiles cintc. Stage one is the compiler built by a seed, stage two is the compiler compiled by stage one, and stage three is the compiler compiled by stage two. The C that stage one and stage two emit is identical, byte for byte, so stages two and three are built from the same C, and that C is identical again when the whole exercise is repeated under GCC and Clang on x86-64, under MSVC on Windows, and under Apple Clang on arm64. That is what the receipts in the repository record and what the source identity in the footer of every page names. It is the claim the whole site rests on, and it is a claim about bytes, so it can be checked by anyone with the sources and a compiler, once the sources and receipts are published, which they will be with the first release.
In this page the reference runs every program on the site and anything you write in the box: scripts and programs with main, structs, the checked, saturating and wrapping operators, muldiv, div_round and isqrt, arrays, views and slices, kernels, and the integers wider than 64 bits. Of the programs on the site, the compiler that emitted the C here compiles all but five, the two slice programs, the slices and kernel tutorials and the 128-bit orbit, and refuses one more, caught twice, on purpose. The C for the papers, built with GCC, Clang, MSVC and Apple Clang, prints the same bytes as the reference, and the tables in those papers show it. The compiler itself is not published yet. Its sources and receipts will be with the first release, and until then the lower box shows what it produced, not something you can produce.
The compiler that emitted the C on this site does not accept kernels, the data-parallel form, or the wide integers above 64 bits, or every form of view, and the reference does. The compiler since then accepts kernels, views of rank one to four, and slices, and runs kernels on the CPU and, through CUDA, on an NVIDIA GPU, although that GPU path has not yet passed the tests that would make it a supported backend. The wide integers above 64 bits still run only in the reference for now. There is no standard library beyond the built-ins, no package manager, and no debugger beyond the fault record, which in fairness tells you more than most debuggers do. These are listed here so that nothing on the site has to be read twice.
cint grew out of a simulation project that needed the same state bytes on every machine it ran on and found that no amount of care with floating point would give them. The arithmetic was made integer and exact, and the language followed. The checked-integer rules were written as a specification first, the reference second, and the compiler third, and the order is why the two agree.
Harriett Little. cint, an introduction. integerc.dev, 2026. https://integerc.dev/papers/cint/
Harriett Little
October 2026