Narrow the crossing time
A daily bracket leaves as much as a day of uncertainty about the event time. We can narrow it without guessing the Sun’s speed: sample the midpoint, retain the half that still brackets zero, and repeat. Finally we translate the relative offset back into an epoch.
Before this lesson
Read “Locate a crossing interval.” Keep endpoints in increasing time order and retain the signed difference at the lower endpoint. All examples use invented continuous curves with finite samples.
What you will learn
You will carry out midpoint refinement, calculate its stopping width, and interpret the returned time without confusing numerical resolution with astronomical accuracy.
Dotted-underlined terms open a definition beside the text. Select one to read more, then close it to continue.
Each step has its own check. Pass every step to complete the lesson. Your answers and checked steps are saved in this browser, so you can continue after leaving or reloading.
1. Keep the half that contains the crossing
Start with [2, 3] days and the toy difference d − 2.25 degrees. The midpoint is (2 + 3) / 2 = 2.5 days, where the difference is +0.25°. The lower endpoint has difference −0.25°, so the midpoint has the other sign. Keep [2, 2.5]. Its next midpoint is 2.25 days, where the difference is exactly zero, and the implementation returns it immediately.
mid = (lo + hi) / 2; if sign(difference(mid)) = sign(difference(lo)), replace lo; otherwise replace hi
For a crossing at 2.7 days instead, the midpoint 2.5 has negative difference, matching the lower endpoint. Replace lo with 2.5 and retain [2.5, 3]. This is why the algorithm needs lo_diff from the correctly ordered bracket. It does not assume that increasing time means increasing longitude; matching signs chooses the half for either trend.
Each replacement halves the interval width. After n replacements, an initial width W days has become W / 2ⁿ days. The engine continues while hi − lo is greater than 1/86,400 day, which equals one second. Starting with one day, 16 halvings leave 1.318359375 seconds; 17 leave 0.6591796875 seconds. Thus 17 replacements suffice unless an exact-zero midpoint returns sooner.
epsilon = 1 / 86,400 day; Wₙ = W₀ / 2ⁿ; final offset = (lo + hi) / 2
When the width is already one second or less, the loop does not sample another midpoint; it returns the midpoint of the final interval. It tests time width, not an angular-error tolerance. Under a valid continuous bracket, that midpoint lies at most half the final width from a contained zero. This is a conditional numerical bound, not an absolute accuracy specification for the fitted Sun.
What the familiar method guarantees
The National Institute of Standards and Technology describes bisection as narrowing a root interval. Its numerical-method reference supports the method, without establishing a single historical inventor here. This implementation adds its own one-second threshold and exact-zero shortcut. The usual argument requires continuity and finite evaluations; the current midpoint loop has no NaN rejection or special recovery branch.
See the teaching TypeScript
type Bracket = { lo: number; hi: number; loSign: number };
const refine = (bracket: Bracket, midpointDifference: number): Bracket => {
const mid = (bracket.lo + bracket.hi) / 2;
const sign = midpointDifference < 0 || Object.is(midpointDifference, -0) ? -1 : 1;
return sign === bracket.loSign ? { lo: mid, hi: bracket.hi, loSign: sign } : { ...bracket, hi: mid };
};
// Apply only after checking that the finite midpoint difference is not zero.
const remainingSeconds = (initialDays: number, halvings: number): number => initialDays * 86400 / 2 ** halvings;Finite, correctly labeled inputs are assumed. This demonstrates the arithmetic; it does not fetch data or replace the engine.
Connect this step to the source
src/astro/find_moment.rs
bisect
Paths refer to the astrology-engine repository. Examples use invented inputs; a successful exercise is not an astronomical-accuracy test.
Sources for this section
Apply this step
Answer every part, then check. You can retry as often as you like.
2. Put the event back on the time axis
The solver returns a relative number of days. The public wrapper adds that duration to the same epoch used for sampling. An offset of +2.25 days is +194,400 seconds: two days plus six hours. An offset of −2.25 days is the same duration earlier. The sign follows time direction, and the unit remains a duration until it is added to an epoch.
event epoch = starting epoch + Duration::from_days(found offset)
Suppose a toy time axis labels the start as 1,000,000 seconds and the solver returns −0.25 day. The duration is −21,600 seconds, so the event label is 978,400 seconds on that same axis. This is ordinary duration arithmetic, not a conversion between UTC and ephemeris time. The real wrapper uses Epoch and the time library instead of manually editing a calendar string.
The wrapper maps Some(offset) to Some(epoch) and leaves None as None, all inside the admitted request’s Ok result. It does not replace a missing event with the starting epoch. That distinction matters because offset zero is a valid result when a search branch finds the target at its start.
A narrow bracket addresses the solver’s time resolution. Errors in the ephemeris, polynomial approximation, coordinate model, or continuity of samples remain separate. Even floating-point equality with the target is equality in the fitted model, rather than evidence of an exact observed event. The epoch conversion and option mapping are local software policies; their source is the current wrapper, with no invented historical attribution.
See the teaching TypeScript
const toyEventSeconds = (startSeconds: number, offsetDays: number | undefined): number | undefined => offsetDays === undefined ? undefined : startSeconds + offsetDays * 86400;Finite, correctly labeled inputs are assumed. This demonstrates the arithmetic; it does not fetch data or replace the engine.
Connect this step to the source
src/search.rs
find_sun_crossing
Paths refer to the astrology-engine repository. Examples use invented inputs; a successful exercise is not an astronomical-accuracy test.
Sources for this section
Apply this step
Answer every part, then check. You can retry as often as you like.
Your lesson checks
0 of 2 steps passed.
Use the feedback beside each check to retry any unfinished step.