{
  "schemaVersion": 1,
  "slug": "fraction-calculator",
  "category": "math",
  "kind": "implementation",
  "independentValidation": false,
  "implementationHash": "38c47d20ec17a151291246c980c925dd73cd51b20de7f113ca91c56713eb4666",
  "provenance": "Generated from the calculation contract used by the published page. Publication is not external validation.",
  "sourceFiles": [
    "data/calculators/fraction-calculator.json",
    "src/engine.js"
  ],
  "runtimeSource": "/sources/engine.txt",
  "runtimeHash": "5c888d8898afbdee36267bb9977829e1e2ac568f6677c8ee87469c139864645c",
  "scope": "The compute function records implemented equations, constants, lookup tables and custom rules. Inputs record defaults and allowed values; outputs record precision and units. Defaults are examples, not recommendations. General background references are not evidence for this specific algorithm.",
  "publishedFormula": {
    "formula": "+/-: n/d = (n1 x d2 +/- n2 x d1)/(d1 x d2); x: n = n1 x n2, d = d1 x d2; /: n = n1 x d2, d = d1 x n2; -> (n/g)/(d/g), g = gcd(|n|,|d|)",
    "vars": [
      [
        "n1",
        "first numerator"
      ],
      [
        "d1",
        "first denominator"
      ],
      [
        "n2",
        "second numerator"
      ],
      [
        "d2",
        "second denominator"
      ],
      [
        "op",
        "operation: + - x /"
      ],
      [
        "g",
        "greatest common divisor"
      ]
    ],
    "note": "All four numerator and denominator inputs must be integers. The result is reduced with the Euclidean GCD; a zero denominator or division by a zero fraction is invalid."
  },
  "externalEvidence": {
    "reviewedAt": "2026-10-28",
    "sources": [
      {
        "name": "Wolfram MathWorld — Greatest Common Divisor",
        "url": "https://mathworld.wolfram.com/GreatestCommonDivisor.html"
      }
    ],
    "implementationHash": "38c47d20ec17a151291246c980c925dd73cd51b20de7f113ca91c56713eb4666",
    "basis": "Cross-multiply numerators for addition/subtraction; multiply directly or by the reciprocal for multiplication/division. Normalize denominator sign and divide both parts by their greatest common divisor. P1 consolidation retains the core model and adds input modes or derived outputs. The migration report records the input/output union and known-answer checks.",
    "limitations": "Integer inputs are limited to ±1,000,000. Zero denominators, division by a zero numerator and unsupported operations are rejected. Decimal output is rounded. Added display totals and migration adapters are implementation behavior, not independently validated claims."
  },
  "contract": {
    "compute": "const mergedResult=(()=>{if((true&&![\"add\", \"sub\", \"mul\", \"div\"].includes(String(op))))return{__error:'unavailable'};\nif((true&&(!Number.isFinite(n1)||n1<-1000000||n1>1000000))||(true&&(!Number.isFinite(d1)||d1<-1000000||d1>1000000))||(true&&(!Number.isFinite(n2)||n2<-1000000||n2>1000000))||(true&&(!Number.isFinite(d2)||d2<-1000000||d2>1000000)))return{__error:'unavailable'};\nif (!['add','sub','mul','div'].includes(op) || ![n1,d1,n2,d2].every(x=>Number.isInteger(x)&&Math.abs(x)<=1000000) || d1===0 || d2===0 || (op==='div' && n2===0)) return { result:null, decimal:null, numerator:null, denominator:null, __error:'unavailable' }; const gcd=(x,y)=>{ x=Math.abs(x); y=Math.abs(y); while(y){ const t=y; y=x%y; x=t; } return x||1; }; let n, d; if(op==='add'){ n=n1*d2+n2*d1; d=d1*d2; } else if(op==='sub'){ n=n1*d2-n2*d1; d=d1*d2; } else if(op==='mul'){ n=n1*n2; d=d1*d2; } else { n=n1*d2; d=d1*n2; } if(d<0){ n=-n; d=-d; } const g=gcd(n,d), sn=n/g, sd=d/g; const whole=Math.trunc(sn/sd),rem=Math.abs(sn%sd),mixedNumber=rem===0?String(whole):Math.abs(sn)<sd?sn+'/'+sd:(sn<0&&whole===0?'-':'')+whole+' '+rem+'/'+sd; const commonDenominator=(op==='add'||op==='sub')?Math.abs(d1/gcd(d1,d2)*d2):null;return {mixedNumber,commonDenominator,reciprocal:sn===0?null:(sn<0?'-':'')+sd+'/'+Math.abs(sn), result: sd===1 ? String(sn) : sn+'/'+sd, decimal:sn/sd, numerator:sn, denominator:sd };\n})();return mergedResult.__error?{\"result\":null,\"decimal\":null,\"numerator\":null,\"denominator\":null,\"mixedNumber\":null,\"reciprocal\":null,\"commonDenominator\":null,...mergedResult}:mergedResult;",
    "inputs": [
      {
        "name": "n1",
        "type": "number",
        "default": 3,
        "min": -1000000,
        "max": 1000000,
        "step": 1,
        "requiredValue": true,
        "strictRange": true
      },
      {
        "name": "d1",
        "type": "number",
        "default": 4,
        "min": -1000000,
        "max": 1000000,
        "step": 1,
        "requiredValue": true,
        "strictRange": true
      },
      {
        "name": "op",
        "type": "select",
        "default": "add",
        "options": [
          {
            "value": "add"
          },
          {
            "value": "sub"
          },
          {
            "value": "mul"
          },
          {
            "value": "div"
          }
        ]
      },
      {
        "name": "n2",
        "type": "number",
        "default": 5,
        "min": -1000000,
        "max": 1000000,
        "step": 1,
        "requiredValue": true,
        "strictRange": true
      },
      {
        "name": "d2",
        "type": "number",
        "default": 6,
        "min": -1000000,
        "max": 1000000,
        "step": 1,
        "requiredValue": true,
        "strictRange": true
      }
    ],
    "outputs": [
      {
        "name": "result",
        "precision": 0,
        "unit": "",
        "type": "text"
      },
      {
        "name": "decimal",
        "precision": 6,
        "unit": "",
        "trimTrailingZeros": true
      },
      {
        "name": "numerator",
        "precision": 0,
        "unit": ""
      },
      {
        "name": "denominator",
        "precision": 0,
        "unit": ""
      },
      {
        "name": "mixedNumber",
        "precision": 2,
        "unit": "",
        "type": "text",
        "optional": true
      },
      {
        "name": "reciprocal",
        "precision": 2,
        "unit": "",
        "type": "text",
        "optional": true
      },
      {
        "name": "commonDenominator",
        "precision": 0,
        "unit": "",
        "optional": true
      }
    ],
    "interpret": null
  }
}
