Scale raw test score calculator
This raw test score calculator converts one score from an observed minimum and maximum into a chosen target range.
Run — free
The observed minimum becomes the target lowest value, the observed maximum becomes the target highest value, and every score between them keeps the same relative position. It is useful when grades, assessments, rubrics, or legacy reports need a consistent scale without changing the ordering or proportional spacing of results. Enter five numbers and choose the rounding precision to receive both the rescaled score and its normalized position.
What linear score scaling preserves
Linear rescaling changes the labels on a score range while preserving relative position. If a raw score lies halfway between the observed minimum and maximum, its converted score lies halfway between the target lowest and highest values. The same principle applies at every other point: a score one quarter of the way through the observed range lands one quarter of the way through the target range. This makes the method appropriate when the goal is a transparent change of scale rather than a change in ranking, weighting, or difficulty. The calculator maps the two endpoints exactly before rounding, so the observed minimum becomes the target lowest value and the observed maximum becomes the target highest value. Scores between those endpoints remain ordered, and equal raw-score gaps produce equal converted-score gaps. The method does not create a curve, compare a learner with a population, or infer performance standards. It simply expresses the same position on a different numeric range, making its assumptions easy to explain and reproduce.
How to enter the ranges and read the result
Enter the individual raw score, then provide the observed minimum and observed maximum that define the original scale. These endpoints must be different, and the maximum must be greater than the minimum. Next, enter the target lowest and target highest values for the new scale, again in increasing order. The raw score must fall inside the observed range, including either endpoint; rejecting scores outside the range prevents an accidental extrapolation from looking like an ordinary conversion. The result includes the scaled score and a normalized position. A normalized position of zero corresponds to the observed minimum, one corresponds to the observed maximum, and values between zero and one show the proportional location of the raw score. Precision controls the displayed decimal places for these calculated values, from whole numbers through twelve decimal places. The original inputs are also returned so an automated workflow can retain a clear audit record of exactly which ranges produced the result.
When this formula is appropriate and when it is not
Use this calculator when two numeric scales describe the same underlying continuum and the desired transformation should be linear. Common examples include converting classroom points to a reporting band, aligning results from a fixed-form assessment with a local display range, or migrating a historic score field into a system that expects different endpoints. Before applying one conversion to many records, confirm that the observed endpoints are the intended policy endpoints rather than merely the smallest and largest values in an incomplete sample. A sample-dependent minimum or maximum can change when new results arrive, causing previously converted scores to shift. Linear rescaling is not a substitute for equating different test forms, percentile ranks, standard scores, item-response modeling, grading curves, or pass/fail standard setting. Those methods use information beyond two endpoints and answer different questions. Keep the unrounded source score when possible, select enough precision for downstream work, and round only the reported result so repeated transformations do not accumulate avoidable rounding error.
What you can do with it
Convert points to a reporting scale
Map scores from a fixed point range onto the numeric range required by a gradebook or reporting template.
Normalize a legacy assessment field
Express historic scores on a new range while preserving each result's proportional position and ordering.
Document a transparent score transformation
Return the converted value, normalized position, endpoints, and precision for a reproducible audit trail.
FAQ
What formula does the calculator use?
It computes the raw score's position as (raw score − observed minimum) divided by (observed maximum − observed minimum), then applies that position to the target range.
Does the observed minimum always map to the target lowest value?
Yes. The two observed endpoints map exactly to their corresponding target endpoints before the requested rounding is applied.
Can I enter a raw score outside the observed range?
No. The calculator rejects out-of-range scores so extrapolation cannot be mistaken for an ordinary within-range conversion.
Is this the same as grading on a curve?
No. A grading curve depends on a distribution or policy. Linear rescaling uses only two source endpoints and two target endpoints.
How should I choose precision?
Use enough decimal places for the reporting or downstream calculation. Keep the original raw score separately when later calculations need more precision.
What does it cost?
The calculator runs free in the browser. API requests cost $0.002 each.
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/edu/scale-raw-score \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"raw_score":42,"observed_min":10,"observed_max":50,"target_lowest":0,"target_highest":100}'const res = await fetch("https://api.kit.forhosting.com/edu/scale-raw-score", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"raw_score": 42,
"observed_min": 10,
"observed_max": 50,
"target_lowest": 0,
"target_highest": 100
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/edu/scale-raw-score",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"raw_score": 42,
"observed_min": 10,
"observed_max": 50,
"target_lowest": 0,
"target_highest": 100
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/edu/scale-raw-score", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"raw_score":42,"observed_min":10,"observed_max":50,"target_lowest":0,"target_highest":100}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"raw_score":42,"observed_min":10,"observed_max":50,"target_lowest":0,"target_highest":100}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/edu/scale-raw-score", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"raw_score": 42,
"observed_min": 10,
"observed_max": 50,
"target_lowest": 0,
"target_highest": 100
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "edu.scale_raw_score",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |