// Copyright (c) 2026 Petr BalvĂ­n (https://petrbalvin.org) // SPDX-License-Identifier: MIT package core import "testing" // TestInterpolateQueryOnKnotTakesTheLeftSegment pins the segment choice // for a query landing exactly on a knot: the bisection takes the first // knot at or above the query, so the left segment is used and the query // sits at its upper end with t exactly 1. With a lower y of zero the // interpolation is exactly the knot's own y. A repeated knot makes the // choice observable: the query returns the first of the repeated ys, // where the right segment would return the second. func TestInterpolateQueryOnKnotTakesTheLeftSegment(t *testing.T) { xs := mustFloats(t, []float64{0, 1, 2, 3}) ys := mustFloats(t, []float64{0, 10, 20, 30}) q := mustFloats(t, []float64{1, 2}) out, err := Interpolate(xs, ys, q) if err != nil { t.Fatalf("Interpolate: %v", err) } for i, w := range []float64{10, 20} { if got := out.FloatAt(i); got != w { t.Fatalf("query on knot %v answered %v, want exactly %v", q.FloatAt(i), got, w) } } dup, err := Interpolate( mustFloats(t, []float64{0, 1, 1, 2}), mustFloats(t, []float64{10, 20, 30, 40}), mustFloats(t, []float64{1})) if err != nil { t.Fatalf("Interpolate: %v", err) } if got := dup.FloatAt(0); got != 20 { t.Fatalf("query on a repeated knot answered %v, want the left segment's 20", got) } }