Make a backward Sun search faster
Finding an earlier crossing by sampling every day works, but it may require many samples before a bracket appears. The engine can first estimate how far back to look using an average angular speed. It checks the fitted curve around that estimate, then either refines a bracket or returns to the daily search you already know.
Before this lesson
Read “Narrow the crossing time.” You will reuse normalized angles, signed differences, the real-crossing test and bisection. Examples below are invented continuous curves with finite samples, not measured solar events.
What you will learn
You will calculate a backward time estimate, test its eight-day bracket, and trace when the engine uses or abandons this shortcut.
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. Use average motion to choose a place to look
Suppose the starting Sun longitude is 10° and the target is 350°. Looking backward along increasing solar longitude, we pass through 0° and reach 350° after retracing 20°. Ordinary subtraction gives −340°, so normalize the difference into [0°, 360°): −340° + 360° = 20°. This backward arc describes how much angular motion we intend to undo. It is not the signed shortest difference used to test a crossing.
arc = normalize360(start longitude − target longitude)
To turn that angle into an estimated duration, the implementation uses a fixed average speed of 360 / 365.2422 degrees per day, about 0.985647°. Dividing 20° by this speed gives 20.291233 days. The search is backward, so its relative offset is negative: −20.291233 days. This rate is a seed constant in the current code; it is neither a derivative of the fitted curve nor a promise that the Sun moves uniformly.
mean motion = 360 / 365.2422 °/day; guess = −arc / mean motion days
The guess only tells us where to look. The engine samples four days before and four days after it, giving [−24.291233, −16.291233] days in increasing time order. The interval is eight days wide. Using an invented constant-speed curve with longitude normalize360(10 + mean motion × d), the signed differences from 350° are about −3.942589° and +3.942589°. The signs differ and their absolute magnitudes add to about 7.885179°, below 180°, so this bracket passes the same real-crossing test as the daily scan.
lo = guess − 4 days; hi = guess + 4 days
accept bracket when signs differ AND |difference(lo)| + |difference(hi)| < 180°
The accepted bracket goes to bisection, which samples the fitted curve rather than the average-speed line. An eight-day width needs at most 20 halvings to become no wider than one second: 8 × 86,400 / 2²⁰ = 0.6591796875 seconds. An exact-zero midpoint can finish sooner. The seed can save daily samples, but the refinement and its conditional resolution bound remain those of the previous lesson.
Why this is an estimate rather than a new orbit model
Bisection is a standard numerical method documented by the National Institute of Standards and Technology. The fixed rate, four-day half-width and seed-before-scan ordering are local engineering choices documented by this implementation. The cited sources do not establish a named inventor or an origin story for this particular shortcut. No claim of astronomical accuracy follows from the worked constant-speed example.
See the teaching TypeScript
const normalize360 = (angle: number): number => ((angle % 360) + 360) % 360;
const seedBracket = (start: number, target: number): { arc: number; guess: number; lo: number; hi: number } => {
const arc = normalize360(start - target);
const guess = -arc / (360 / 365.2422);
return { arc, guess, lo: guess - 4, hi: guess + 4 };
};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
seed_backward_sun
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. Keep the shortcut behind the crossing test
A fast guess is useful only if it leads to an accepted bracket. For a backward Sun search the dispatcher samples the starting longitude, computes the arc, and tries the seed. If its endpoint test succeeds, it returns the bisection result directly. If the endpoint test fails, it starts the daily backward scan at offset zero. It does not widen the seed, repeatedly change the average rate, or return the guess as an event.
Consider a second invented curve, longitude normalize360(10 + 0.5 × d), with target 350°. The same start and target produce the same guess, but the actual crossing is at −40 days. Both seed endpoints have positive signed differences, about +7.854383° and +11.854383°. There is no seed bracket, so the engine falls back. At offset −40 the difference is positive zero, whose Rust signum is +1, matching the positive difference at −39. The scan therefore continues to −41, where the difference is negative, and refines [−41, −40]. Here signum means the sign indicator used by the implementation; positive zero is treated as +1. This example makes the policy visible; it is not a realistic solar-speed model.
backward AND is_sun → try seed; seed fails → daily scan; all other cases → daily scan
Forward Sun searches skip the seed, as do internal helper calls with is_sun = false. The helper accepts a generic sampling function, but the public find_sun_crossing API always samples the Sun and supplies is_sun = true. That internal flag does not expose a public search API for other planets.
“Backward” describes which branch is chosen; the seed interval itself is not clipped at zero. With a zero arc its endpoints are −4 and +4 days. On the constant-speed toy curve with start exactly at the target, the bracket passes and bisection returns zero. For a small arc, hi can be positive. Nor is the seed clipped to the daily scan’s 730-day window or to dataset bounds. The wrapper’s fixed 89-day lookback admission guard does not guarantee usable samples at every seed endpoint for arbitrary targets.
The useful result of this lesson is a separation of jobs. Average motion chooses a neighborhood; endpoint samples decide whether it contains an accepted crossing; bisection locates a time in that bracket. The fallback preserves the existing daily-search policy when the estimate does not help. The particular ordering and flags have their provenance in the current source, without an additional historical attribution.
See the teaching TypeScript
type SearchBranch = 'try-seed' | 'daily-scan';
const initialBranch = (direction: 'backward' | 'forward', isSun: boolean): SearchBranch =>
direction === 'backward' && isSun ? 'try-seed' : 'daily-scan';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
find_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.