@@ -1113,4 +1113,77 @@ static_assert(std::numeric_limits<qp_hmax>::max().quantity_from(halfbound_max_or
11131113static_assert (std::numeric_limits<qp_hmax>::lowest().quantity_from(halfbound_max_origin).numerical_value_in(m) ==
11141114 std::numeric_limits<double >::lowest());
11151115
1116+ // ============================================================================
1117+ // Large-delta tests: deltas much larger than the range width.
1118+ //
1119+ // wrap_to_range and reflect_in_range are total functions — defined for all
1120+ // inputs, not just "one boundary crossing". These tests verify that adding a
1121+ // delta that covers several full periods still yields the correct result.
1122+ // (clamp_to_range is excluded: it is idempotent past the boundary — any
1123+ // value beyond [min, max] produces the same saturated result regardless of
1124+ // how far it overshoots, so there is nothing new to test for large deltas.)
1125+ // ============================================================================
1126+
1127+ // ---- wrap_to_range: range [-180°, 180°), period = 360° ---------------------
1128+
1129+ // 3 full rotations + 45°: same as 45°.
1130+ static_assert (qp_wrap(3 * 360.0 * deg + 45.0 * deg, wrap_origin).quantity_from(wrap_origin) == 45.0 * deg);
1131+
1132+ // 3 full rotations in the negative direction + 45°: same as 45°.
1133+ static_assert (qp_wrap(-3 * 360.0 * deg + 45.0 * deg, wrap_origin).quantity_from(wrap_origin) == 45.0 * deg);
1134+
1135+ // 2.5 rotations (= 900°): same as 180° → at upper exclusive boundary → wraps to -180°.
1136+ static_assert (qp_wrap(2.5 * 360.0 * deg, wrap_origin).quantity_from(wrap_origin) == -180.0 * deg);
1137+
1138+ // operator+=: start at 90°, add 3 full rotations + 30° (= 1110°) → lands at 120°.
1139+ consteval bool wrap_large_delta_assign ()
1140+ {
1141+ auto pt = qp_wrap (90.0 * deg, wrap_origin);
1142+ pt += 3 * 360.0 * deg + 30.0 * deg;
1143+ return pt.quantity_from (wrap_origin) == 120.0 * deg;
1144+ }
1145+ static_assert (wrap_large_delta_assign());
1146+
1147+ // ---- reflect_in_range: range [-90°, 90°], period = 360° -------------------
1148+ // The period of reflect_in_range{[a,b]} is 2*(b−a) = 2*180° = 360°.
1149+ // After an integer number of periods the point returns to the same position.
1150+
1151+ // Half a period (180°): the "fold-back" point — lands at 0°.
1152+ static_assert (qp_reflect(180.0 * deg, reflect_origin).quantity_from(reflect_origin) == 0.0 * deg);
1153+
1154+ // 3/4 of a period (270°): bounces off max, then off min → lands at -90°.
1155+ static_assert (qp_reflect(270.0 * deg, reflect_origin).quantity_from(reflect_origin) == -90.0 * deg);
1156+
1157+ // 3 full periods + 45° (= 1125°): same as 45°.
1158+ static_assert (qp_reflect(3 * 360.0 * deg + 45.0 * deg, reflect_origin).quantity_from(reflect_origin) == 45.0 * deg);
1159+
1160+ // Negative direction: -(1 full period + 45°) = -405° → same as -45°.
1161+ static_assert (qp_reflect(-1 * 360.0 * deg - 45.0 * deg, reflect_origin).quantity_from(reflect_origin) == -45.0 * deg);
1162+
1163+ // operator+=: start at 0°, add 1.5 periods (= 540°) → same as adding 180° → 0°.
1164+ consteval bool reflect_large_delta_assign ()
1165+ {
1166+ auto pt = qp_reflect (0.0 * deg, reflect_origin);
1167+ pt += 1.5 * 360.0 * deg;
1168+ return pt.quantity_from (reflect_origin) == 0.0 * deg;
1169+ }
1170+ static_assert (reflect_large_delta_assign());
1171+
1172+ // ---- wrap_to_range: time-of-day [0 s, 86400 s), period = 86400 s ----------
1173+
1174+ // 3 full days + 1 hour (= 262800 s): wraps to 3600 s = 01:00.
1175+ static_assert (time_of_day(3 * 86400.0 * s + 3600.0 * s, midnight).quantity_from(midnight) == 3600.0 * s);
1176+
1177+ // Negative: 3 full days before midnight + 1 hour before end = -3*86400+82800 = -176400 s → 82800 s = 23:00.
1178+ static_assert (time_of_day(-3 * 86400.0 * s + 82800.0 * s, midnight).quantity_from(midnight) == 82800.0 * s);
1179+
1180+ // operator+=: start at 23:00 (82800 s), add 3 days + 2 hours (= 266400 s) → lands at 01:00 (3600 s).
1181+ consteval bool time_of_day_multiday_assign ()
1182+ {
1183+ auto t = time_of_day (82800.0 * s, midnight); // 23:00
1184+ t += 3 * 86400.0 * s + 2 * 3600.0 * s; // +3 days 2 hours
1185+ return t.quantity_from (midnight) == 3600.0 * s;
1186+ }
1187+ static_assert (time_of_day_multiday_assign());
1188+
11161189} // namespace
0 commit comments