{
  "schemaVersion": 1,
  "slug": "gpa-calculator",
  "category": "math",
  "kind": "implementation",
  "independentValidation": false,
  "implementationHash": "221e3c67a7b2f401b327e31f06d8702803478663fe17e55c4a033c3a856364e1",
  "provenance": "Generated from the calculation contract used by the published page. Publication is not external validation.",
  "sourceFiles": [
    "data/calculators/gpa-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": "GPA = Σ(p_k c_k) / Σ c_k; percentage = GPA ÷ 4 × 100",
    "vars": [
      [
        "p_k",
        "Grade points for course k (A+ = 4.0 … F = 0)"
      ],
      [
        "c_k",
        "Credits for course k"
      ],
      [
        "GPA",
        "Grade point average"
      ]
    ],
    "note": "GPA = Σ(grade points × course credits) ÷ Σ(course credits). The displayed percentage is GPA ÷ 4.0 × 100 for this model only; institutional scales and exclusions vary."
  },
  "externalEvidence": {
    "reviewedAt": "2026-10-12",
    "sources": [
      {
        "name": "University of Maryland — GPA calculation and grade points",
        "url": "https://gradschool.umd.edu/sites/default/files/2023-06/gpa_letter-grade.pdf"
      }
    ],
    "referenceRole": "definition",
    "implementationHash": "221e3c67a7b2f401b327e31f06d8702803478663fe17e55c4a033c3a856364e1",
    "basis": "GPA = Σ(p_k c_k) / Σ c_k; percentage = GPA ÷ 4 × 100",
    "limitations": "The references explain definitions and methods; any extra preset must be checked against the assumptions on this page."
  },
  "contract": {
    "compute": "const map={'A+':4,'A':4,'A-':3.7,'B+':3.3,'B':3,'B-':2.7,'C+':2.3,'C':2,'C-':1.7,'D+':1.3,'D':1,'D-':0.7,'F':0}; const gs=String(grades).split(/[,\\n]+/).map(s=>s.trim().toUpperCase()).filter(Boolean); const raw=String(credits).split(/[,\\s]+/).filter(Boolean); const cs=raw.map(Number); const invalid={__error:'gpa',gpa:null,totalCredits:null,qualityPoints:null,courses:null,percentage:null}; if(!gs.length || gs.length!==cs.length || gs.some(g=>map[g]===undefined) || cs.some(c=>!Number.isFinite(c)||c<=0)) return invalid; let qp=0,tc=0; for(let k=0;k<gs.length;k++){ qp+=map[gs[k]]*cs[k]; tc+=cs[k]; } const gpa=qp/tc; return {gpa,totalCredits:tc,qualityPoints:qp,courses:gs.length,percentage:gpa/4*100};",
    "inputs": [
      {
        "name": "grades",
        "type": "text",
        "default": "A, A-, B+, B, B-",
        "step": 1
      },
      {
        "name": "credits",
        "type": "text",
        "default": "3, 4, 3, 3, 2",
        "step": 1
      }
    ],
    "outputs": [
      {
        "name": "gpa",
        "precision": 4,
        "unit": ""
      },
      {
        "name": "totalCredits",
        "precision": 2,
        "unit": ""
      },
      {
        "name": "qualityPoints",
        "precision": 2,
        "unit": ""
      },
      {
        "name": "courses",
        "precision": 0,
        "unit": ""
      },
      {
        "name": "percentage",
        "precision": 1,
        "unit": "%"
      }
    ],
    "interpret": null
  }
}
