Gram-Schmidt calculator
Paste independent vectors and get an orthonormal basis of the same space: (1, 1, 0), (1, 0, 1) and (0, 0, 3) become three unit vectors at right angles, the first being your first vector rescaled to length 1. Dependent sets are flagged, never hidden. Free in your browser.
- Free
- Runs in your browser
- No sign-up
- Your data stays on your device
Run — free
The Gram-Schmidt process takes a set of linearly independent vectors and returns an orthonormal basis: the same number of vectors, each of unit length, each perpendicular to all the others, spanning exactly the same subspace as the originals. If the vectors are linearly dependent, the calculator says so instead of returning a wrong answer.
What the Gram-Schmidt process actually does
Orthonormal bases make almost every computation in linear algebra easier: projections become dot products, coordinates become trivial, and numerical errors stay small. The Gram-Schmidt process builds one from any independent set. It takes the first vector and rescales it to unit length; that is the first basis vector.
For every vector after that, it subtracts the part that points along each basis vector already found — the projection, computed as a dot product — and then rescales what remains. What remains is, by construction, perpendicular to everything before it. Repeat for all the vectors and you have an orthonormal basis of the same span.
The calculator on this page performs exactly this classical procedure: you supply vectors as arrays of numbers, all of the same dimension, and you receive the orthonormal vectors in the corresponding order. The first output vector is just your first input vector normalized; each later output is the component of your input that is genuinely new, made unit length. Because the whole computation is plain arithmetic on doubles, the same input always produces the same output, which is what makes it safe to embed in automated pipelines.
Why linear dependence is an error, not a result
Gram-Schmidt has no meaningful answer when the input vectors are linearly dependent. If one vector is a combination of the ones before it, subtracting the projections removes it entirely: nothing is left to normalize, and dividing by a zero-length leftover would be nonsense. A calculator that silently dropped that vector, or returned a zero row, would hand you a basis that does not match the count of your inputs and hides a modelling mistake.
The same check catches the obvious edge cases: a zero vector, a repeated vector, or more vectors than the dimension of the space, which is dependent by counting alone. The tolerance is numerical rather than exact, so nearly-dependent sets produced by measurement noise are flagged too. If you expected the set to be independent, the error message tells you which vector to inspect, which is usually enough to find the duplicated row or the copy-paste slip in your data.
Practical details: input shape, precision and limits
The input is a single field, vectors, given as an array of arrays of finite numbers — one inner array per vector, every one of the same dimension, up to 50 vectors of dimension up to 50. The output reports the dimension, how many orthonormal vectors were produced, and the basis itself as an array of unit vectors.
Components are rounded to six decimal places, so results are stable across machines and safe to compare or store; each returned vector has Euclidean norm 1 and is orthogonal to its companions up to that rounding. The computation is O(n squared times the dimension), which for these limits is microseconds of work, so the latency you observe is essentially transport, not arithmetic.
A useful sanity check before sending data: no vector may be the zero vector, no two vectors may be equal, and the number of vectors cannot exceed the dimension. For heavily ill-conditioned sets in serious numerical work, a modified Gram-Schmidt or a Householder QR offers extra stability, but for the sizes this calculator accepts the classical process is accurate well beyond the six decimals it reports.
What you can do with it
Orthogonalize directions in a graphics or simulation project
Turn nearly-orthogonal frame vectors into a true orthonormal basis before composing rotations, so rounding drift does not accumulate.
Prepare a basis for a least-squares or projection step
Project data onto a subspace by dotting with orthonormal basis vectors instead of solving a linear system each time.
Check homework and teaching examples
Verify a hand-worked Gram-Schmidt exercise step by step, and see exactly which vector breaks independence when the set is dependent.
FAQ
What does it cost?
On this page it runs free in your browser with the same code.
What input does it expect?
A vectors field: an array of arrays of finite numbers, one inner array per vector, all of the same dimension — up to 50 vectors of dimension up to 50.
How precise is the result?
Components are computed in double precision and rounded to six decimals. Each output vector has unit norm and is orthogonal to the others up to that rounding.
Does the order of the input vectors matter?
Yes. The first output vector is the normalized first input; later outputs are the orthogonalized remainders in the same order, so permuting the input gives a different (equally valid) orthonormal basis.
What happens if my vectors are linearly dependent?
The calculator stops and tells you which vector adds no new direction, instead of dropping it or returning a row of zeros. A zero vector, a repeated vector or more vectors than the dimension all count as dependent.
Related tools
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/math/gram-schmidt \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"vectors":[[1,1,0],[1,0,1],[0,0,3]]}'const res = await fetch("https://api.kit.forhosting.com/math/gram-schmidt", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"vectors": [
[
1,
1,
0
],
[
1,
0,
1
],
[
0,
0,
3
]
]
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/math/gram-schmidt",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"vectors": [
[
1,
1,
0
],
[
1,
0,
1
],
[
0,
0,
3
]
]
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/math/gram-schmidt", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"vectors":[[1,1,0],[1,0,1],[0,0,3]]}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"vectors":[[1,1,0],[1,0,1],[0,0,3]]}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/math/gram-schmidt", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"vectors": [
[
1,
1,
0
],
[
1,
0,
1
],
[
0,
0,
3
]
]
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "math.gram_schmidt",
"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.
Limits
max_vectors | 50 |
max_dimension | 50 |
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. |
Technical notes
Paste your vectors here and get the orthonormal basis computed step by step in your browser, or call the API to orthogonalize vector sets inside a script, a spreadsheet pipeline or a numerical workflow.
Why linear dependence is an error, not a result
This endpoint treats dependence as a contract violation: it checks, in order, whether each vector contributes a new direction, and if vector k lies in the span of the previous ones it answers with an invalid_input error naming the offending vector — and an error call is not billed.
Technical questions
What happens if my vectors are linearly dependent?
The request fails with an invalid_input error that names the first vector lying in the span of the previous ones. Error calls are not billed.
Can I use it for complex vectors?
No. Only real vectors are accepted; entries must be finite JSON numbers.