use crate::extended::Extended;
use crate::float::{F064, N5, def_walk_helpers};
use crate::hifi::duration::shift_hd;
use hifitime::{Duration as HD, Epoch, TimeScale, UNIX_REF_EPOCH};
#[inline]
fn hd_min_nanos() -> i128 {
HD::MIN.total_nanoseconds()
}
#[inline]
fn hd_max_nanos() -> i128 {
HD::MAX.total_nanoseconds()
}
#[inline]
fn unix_ref_utc_ns() -> i128 {
UNIX_REF_EPOCH.to_utc_duration().total_nanoseconds()
}
#[inline]
fn unix_min_nanos() -> i128 {
hd_min_nanos()
}
#[inline]
fn unix_max_nanos() -> i128 {
hd_max_nanos() - unix_ref_utc_ns()
}
#[inline]
fn hd_min_secs_f64() -> f64 {
(hd_min_nanos() / 1_000_000_000) as f64
}
#[inline]
fn hd_max_secs_f64() -> f64 {
(hd_max_nanos() / 1_000_000_000) as f64
}
#[inline]
fn unix_min_secs_f64() -> f64 {
(unix_min_nanos() / 1_000_000_000) as f64
}
#[inline]
fn unix_max_secs_f64() -> f64 {
(unix_max_nanos() / 1_000_000_000) as f64
}
#[inline]
fn etaihdur_forward(e: Epoch) -> HD {
e.to_tai_duration()
}
#[inline]
fn etaihdur_back(d: HD) -> Epoch {
Epoch::from_tai_duration(d)
}
crate::iso! {
pub ETAIHDUR : Epoch => HD {
forward: etaihdur_forward,
back: etaihdur_back,
}
}
fn etainano_ceil(e: Extended<Epoch>) -> i128 {
let max_n = hd_max_nanos();
match e {
Extended::NegInf => i128::MIN,
Extended::Finite(e) => e.to_tai_duration().total_nanoseconds(),
Extended::PosInf => max_n + 1,
}
}
fn etainano_inner(n: i128) -> Extended<Epoch> {
let min_n = hd_min_nanos();
let max_n = hd_max_nanos();
if n < min_n {
Extended::NegInf
} else if n > max_n {
Extended::PosInf
} else {
Extended::Finite(Epoch::from_tai_duration(HD::from_total_nanoseconds(n)))
}
}
crate::conn_l! {
pub ETAINANO : Extended<Epoch> => i128 {
ceil: etainano_ceil,
inner: etainano_inner,
}
}
#[inline]
fn shift_epoch_tai(n: i32, e: Epoch) -> Epoch {
Epoch::from_tai_duration(shift_hd(n, e.to_tai_duration()))
}
#[inline]
fn epoch_to_tai_f64(e: Epoch) -> f64 {
e.to_tai_seconds()
}
#[inline]
fn epoch_to_ns(e: Epoch) -> i128 {
e.to_tai_duration().total_nanoseconds()
}
#[inline]
fn epoch_from_ns(n: i128) -> Epoch {
Epoch::from_tai_duration(crate::hifi::duration::hd_from_ns(n))
}
def_walk_helpers!(
f64_etai_walks,
f64,
Epoch,
shift_epoch_tai,
epoch_to_tai_f64,
epoch_to_ns,
epoch_from_ns
);
fn f064etai_ceil(x: F064) -> Extended<Epoch> {
let v = x.into_inner();
if v.is_nan() {
return Extended::PosInf;
}
if v == f64::INFINITY {
return Extended::PosInf;
}
if v == f64::NEG_INFINITY {
return Extended::NegInf;
}
let max_secs = hd_max_secs_f64();
let min_secs = hd_min_secs_f64();
if v > max_secs {
return Extended::PosInf;
}
if v <= min_secs {
return Extended::Finite(Epoch::from_tai_duration(HD::MIN));
}
let est = Epoch::from_tai_seconds(v);
let (z, _) = f64_etai_walks::solve_to_ceil(est, v);
Extended::Finite(z)
}
fn f064etai_inner(e: Extended<Epoch>) -> F064 {
match e {
Extended::NegInf => N5::new(f64::NEG_INFINITY),
Extended::Finite(e) => N5::new(e.to_tai_seconds()),
Extended::PosInf => N5::new(f64::INFINITY),
}
}
crate::conn_l! {
pub F064ETAI : F064 => Extended<Epoch> {
ceil: f064etai_ceil,
inner: f064etai_inner,
}
}
#[cfg(kani)]
pub(crate) fn f64_etai_ceil_walk_steps_for_proof(v: f64) -> (Epoch, u32) {
let est = Epoch::from_tai_seconds(v);
let est_widen = est.to_tai_seconds();
if est_widen >= v {
f64_etai_walks::descend_to_ceil(est, v)
} else {
f64_etai_walks::ascend_to_ceil(est, v)
}
}
#[cfg(kani)]
pub(crate) fn f64_etai_ceil_solve_steps_for_proof(v: f64) -> (Epoch, u32) {
let est = Epoch::from_tai_seconds(v);
f64_etai_walks::solve_to_ceil(est, v)
}
#[inline]
fn eutchdur_forward(e: Epoch) -> HD {
e.to_duration_in_time_scale(TimeScale::UTC)
}
#[inline]
fn eutchdur_back(d: HD) -> Epoch {
Epoch::from_utc_duration(d)
}
crate::iso! {
pub EUTCHDUR : Epoch => HD {
forward: eutchdur_forward,
back: eutchdur_back,
}
}
fn eunxnano_ceil(e: Extended<Epoch>) -> i128 {
let max_n = unix_max_nanos();
match e {
Extended::NegInf => i128::MIN,
Extended::Finite(e) => {
(e.to_duration_in_time_scale(TimeScale::UTC) - UNIX_REF_EPOCH.to_utc_duration())
.total_nanoseconds()
}
Extended::PosInf => max_n + 1,
}
}
fn eunxnano_inner(n: i128) -> Extended<Epoch> {
let min_n = unix_min_nanos();
let max_n = unix_max_nanos();
if n < min_n {
Extended::NegInf
} else if n > max_n {
Extended::PosInf
} else {
let utc_total_ns = n + unix_ref_utc_ns();
let utc_dur = HD::from_total_nanoseconds(utc_total_ns);
Extended::Finite(Epoch::from_utc_duration(utc_dur))
}
}
crate::conn_l! {
pub EUNXNANO : Extended<Epoch> => i128 {
ceil: eunxnano_ceil,
inner: eunxnano_inner,
}
}
#[inline]
fn epoch_to_unix_f64(e: Epoch) -> f64 {
e.to_unix_seconds()
}
def_walk_helpers!(
f64_eutc_walks,
f64,
Epoch,
shift_epoch_tai,
epoch_to_unix_f64,
epoch_to_ns,
epoch_from_ns
);
fn f064eunx_ceil(x: F064) -> Extended<Epoch> {
let v = x.into_inner();
if v.is_nan() {
return Extended::PosInf;
}
if v == f64::INFINITY {
return Extended::PosInf;
}
if v == f64::NEG_INFINITY {
return Extended::NegInf;
}
let unix_max_secs = unix_max_secs_f64();
let unix_min_secs = unix_min_secs_f64();
if v > unix_max_secs {
return Extended::PosInf;
}
if v <= unix_min_secs {
return Extended::Finite(Epoch::from_tai_duration(HD::MIN));
}
let est = Epoch::from_unix_seconds(v);
let (z, _) = f64_eutc_walks::solve_to_ceil(est, v);
Extended::Finite(z)
}
fn f064eunx_inner(e: Extended<Epoch>) -> F064 {
match e {
Extended::NegInf => N5::new(f64::NEG_INFINITY),
Extended::Finite(e) => N5::new(e.to_unix_seconds()),
Extended::PosInf => N5::new(f64::INFINITY),
}
}
crate::conn_l! {
pub F064EUNX : F064 => Extended<Epoch> {
ceil: f064eunx_ceil,
inner: f064eunx_inner,
}
}
use hifitime::{BDT_REF_EPOCH, GPST_REF_EPOCH, GST_REF_EPOCH, QZSST_REF_EPOCH};
#[inline]
fn gpst_ref_tai_ns() -> i128 {
GPST_REF_EPOCH.to_tai_duration().total_nanoseconds()
}
#[inline]
fn qzsst_ref_tai_ns() -> i128 {
QZSST_REF_EPOCH.to_tai_duration().total_nanoseconds()
}
#[inline]
fn gst_ref_tai_ns() -> i128 {
GST_REF_EPOCH.to_tai_duration().total_nanoseconds()
}
#[inline]
fn bdt_ref_tai_ns() -> i128 {
BDT_REF_EPOCH.to_tai_duration().total_nanoseconds()
}
#[inline]
fn gpst_min_nanos() -> i128 {
hd_min_nanos()
}
#[inline]
fn gpst_max_nanos() -> i128 {
hd_max_nanos() - gpst_ref_tai_ns()
}
#[inline]
fn qzsst_min_nanos() -> i128 {
hd_min_nanos()
}
#[inline]
fn qzsst_max_nanos() -> i128 {
hd_max_nanos() - qzsst_ref_tai_ns()
}
#[inline]
fn gst_min_nanos() -> i128 {
hd_min_nanos()
}
#[inline]
fn gst_max_nanos() -> i128 {
hd_max_nanos() - gst_ref_tai_ns()
}
#[inline]
fn bdt_min_nanos() -> i128 {
hd_min_nanos()
}
#[inline]
fn bdt_max_nanos() -> i128 {
hd_max_nanos() - bdt_ref_tai_ns()
}
#[inline]
fn gpst_min_secs_f64() -> f64 {
(gpst_min_nanos() / 1_000_000_000) as f64
}
#[inline]
fn gpst_max_secs_f64() -> f64 {
(gpst_max_nanos() / 1_000_000_000) as f64
}
#[inline]
fn qzsst_min_secs_f64() -> f64 {
(qzsst_min_nanos() / 1_000_000_000) as f64
}
#[inline]
fn qzsst_max_secs_f64() -> f64 {
(qzsst_max_nanos() / 1_000_000_000) as f64
}
#[inline]
fn gst_min_secs_f64() -> f64 {
(gst_min_nanos() / 1_000_000_000) as f64
}
#[inline]
fn gst_max_secs_f64() -> f64 {
(gst_max_nanos() / 1_000_000_000) as f64
}
#[inline]
fn bdt_min_secs_f64() -> f64 {
(bdt_min_nanos() / 1_000_000_000) as f64
}
#[inline]
fn bdt_max_secs_f64() -> f64 {
(bdt_max_nanos() / 1_000_000_000) as f64
}
#[inline]
fn egpshdur_forward(e: Epoch) -> HD {
e.to_gpst_duration()
}
#[inline]
fn egpshdur_back(d: HD) -> Epoch {
Epoch::from_gpst_duration(d)
}
crate::iso! {
pub EGPSHDUR : Epoch => HD {
forward: egpshdur_forward,
back: egpshdur_back,
}
}
fn egpsnano_ceil(e: Extended<Epoch>) -> i128 {
let max_n = gpst_max_nanos();
match e {
Extended::NegInf => i128::MIN,
Extended::Finite(e) => e.to_gpst_duration().total_nanoseconds(),
Extended::PosInf => max_n + 1,
}
}
fn egpsnano_inner(n: i128) -> Extended<Epoch> {
let min_n = gpst_min_nanos();
let max_n = gpst_max_nanos();
if n < min_n {
Extended::NegInf
} else if n > max_n {
Extended::PosInf
} else {
Extended::Finite(Epoch::from_gpst_duration(HD::from_total_nanoseconds(n)))
}
}
crate::conn_l! {
pub EGPSNANO : Extended<Epoch> => i128 {
ceil: egpsnano_ceil,
inner: egpsnano_inner,
}
}
#[inline]
fn epoch_to_gpst_f64(e: Epoch) -> f64 {
e.to_gpst_seconds()
}
def_walk_helpers!(
f64_egps_walks,
f64,
Epoch,
shift_epoch_tai,
epoch_to_gpst_f64,
epoch_to_ns,
epoch_from_ns
);
fn f064egps_ceil(x: F064) -> Extended<Epoch> {
let v = x.into_inner();
if v.is_nan() {
return Extended::PosInf;
}
if v == f64::INFINITY {
return Extended::PosInf;
}
if v == f64::NEG_INFINITY {
return Extended::NegInf;
}
let max_secs = gpst_max_secs_f64();
let min_secs = gpst_min_secs_f64();
if v > max_secs {
return Extended::PosInf;
}
if v <= min_secs {
return Extended::Finite(Epoch::from_tai_duration(HD::MIN));
}
let est = Epoch::from_gpst_seconds(v);
let (z, _) = f64_egps_walks::solve_to_ceil(est, v);
Extended::Finite(z)
}
fn f064egps_inner(e: Extended<Epoch>) -> F064 {
match e {
Extended::NegInf => N5::new(f64::NEG_INFINITY),
Extended::Finite(e) => N5::new(e.to_gpst_seconds()),
Extended::PosInf => N5::new(f64::INFINITY),
}
}
crate::conn_l! {
pub F064EGPS : F064 => Extended<Epoch> {
ceil: f064egps_ceil,
inner: f064egps_inner,
}
}
#[inline]
fn eqzshdur_forward(e: Epoch) -> HD {
e.to_qzsst_duration()
}
#[inline]
fn eqzshdur_back(d: HD) -> Epoch {
Epoch::from_qzsst_duration(d)
}
crate::iso! {
pub EQZSHDUR : Epoch => HD {
forward: eqzshdur_forward,
back: eqzshdur_back,
}
}
fn eqzsnano_ceil(e: Extended<Epoch>) -> i128 {
let max_n = qzsst_max_nanos();
match e {
Extended::NegInf => i128::MIN,
Extended::Finite(e) => e.to_qzsst_duration().total_nanoseconds(),
Extended::PosInf => max_n + 1,
}
}
fn eqzsnano_inner(n: i128) -> Extended<Epoch> {
let min_n = qzsst_min_nanos();
let max_n = qzsst_max_nanos();
if n < min_n {
Extended::NegInf
} else if n > max_n {
Extended::PosInf
} else {
Extended::Finite(Epoch::from_qzsst_duration(HD::from_total_nanoseconds(n)))
}
}
crate::conn_l! {
pub EQZSNANO : Extended<Epoch> => i128 {
ceil: eqzsnano_ceil,
inner: eqzsnano_inner,
}
}
#[inline]
fn epoch_to_qzsst_f64(e: Epoch) -> f64 {
e.to_qzsst_seconds()
}
def_walk_helpers!(
f64_eqzs_walks,
f64,
Epoch,
shift_epoch_tai,
epoch_to_qzsst_f64,
epoch_to_ns,
epoch_from_ns
);
fn f064eqzs_ceil(x: F064) -> Extended<Epoch> {
let v = x.into_inner();
if v.is_nan() {
return Extended::PosInf;
}
if v == f64::INFINITY {
return Extended::PosInf;
}
if v == f64::NEG_INFINITY {
return Extended::NegInf;
}
let max_secs = qzsst_max_secs_f64();
let min_secs = qzsst_min_secs_f64();
if v > max_secs {
return Extended::PosInf;
}
if v <= min_secs {
return Extended::Finite(Epoch::from_tai_duration(HD::MIN));
}
let est = Epoch::from_qzsst_seconds(v);
let (z, _) = f64_eqzs_walks::solve_to_ceil(est, v);
Extended::Finite(z)
}
fn f064eqzs_inner(e: Extended<Epoch>) -> F064 {
match e {
Extended::NegInf => N5::new(f64::NEG_INFINITY),
Extended::Finite(e) => N5::new(e.to_qzsst_seconds()),
Extended::PosInf => N5::new(f64::INFINITY),
}
}
crate::conn_l! {
pub F064EQZS : F064 => Extended<Epoch> {
ceil: f064eqzs_ceil,
inner: f064eqzs_inner,
}
}
#[inline]
fn egsthdur_forward(e: Epoch) -> HD {
e.to_gst_duration()
}
#[inline]
fn egsthdur_back(d: HD) -> Epoch {
Epoch::from_gst_duration(d)
}
crate::iso! {
pub EGSTHDUR : Epoch => HD {
forward: egsthdur_forward,
back: egsthdur_back,
}
}
fn egstnano_ceil(e: Extended<Epoch>) -> i128 {
let max_n = gst_max_nanos();
match e {
Extended::NegInf => i128::MIN,
Extended::Finite(e) => e.to_gst_duration().total_nanoseconds(),
Extended::PosInf => max_n + 1,
}
}
fn egstnano_inner(n: i128) -> Extended<Epoch> {
let min_n = gst_min_nanos();
let max_n = gst_max_nanos();
if n < min_n {
Extended::NegInf
} else if n > max_n {
Extended::PosInf
} else {
Extended::Finite(Epoch::from_gst_duration(HD::from_total_nanoseconds(n)))
}
}
crate::conn_l! {
pub EGSTNANO : Extended<Epoch> => i128 {
ceil: egstnano_ceil,
inner: egstnano_inner,
}
}
#[inline]
fn epoch_to_gst_f64(e: Epoch) -> f64 {
e.to_gst_seconds()
}
def_walk_helpers!(
f64_egst_walks,
f64,
Epoch,
shift_epoch_tai,
epoch_to_gst_f64,
epoch_to_ns,
epoch_from_ns
);
fn f064egst_ceil(x: F064) -> Extended<Epoch> {
let v = x.into_inner();
if v.is_nan() {
return Extended::PosInf;
}
if v == f64::INFINITY {
return Extended::PosInf;
}
if v == f64::NEG_INFINITY {
return Extended::NegInf;
}
let max_secs = gst_max_secs_f64();
let min_secs = gst_min_secs_f64();
if v > max_secs {
return Extended::PosInf;
}
if v <= min_secs {
return Extended::Finite(Epoch::from_tai_duration(HD::MIN));
}
let est = Epoch::from_gst_seconds(v);
let (z, _) = f64_egst_walks::solve_to_ceil(est, v);
Extended::Finite(z)
}
fn f064egst_inner(e: Extended<Epoch>) -> F064 {
match e {
Extended::NegInf => N5::new(f64::NEG_INFINITY),
Extended::Finite(e) => N5::new(e.to_gst_seconds()),
Extended::PosInf => N5::new(f64::INFINITY),
}
}
crate::conn_l! {
pub F064EGST : F064 => Extended<Epoch> {
ceil: f064egst_ceil,
inner: f064egst_inner,
}
}
#[inline]
fn ebdthdur_forward(e: Epoch) -> HD {
e.to_duration_in_time_scale(TimeScale::BDT)
}
#[inline]
fn ebdthdur_back(d: HD) -> Epoch {
Epoch::from_bdt_duration(d)
}
crate::iso! {
pub EBDTHDUR : Epoch => HD {
forward: ebdthdur_forward,
back: ebdthdur_back,
}
}
fn ebdtnano_ceil(e: Extended<Epoch>) -> i128 {
let max_n = bdt_max_nanos();
match e {
Extended::NegInf => i128::MIN,
Extended::Finite(e) => e
.to_duration_in_time_scale(TimeScale::BDT)
.total_nanoseconds(),
Extended::PosInf => max_n + 1,
}
}
fn ebdtnano_inner(n: i128) -> Extended<Epoch> {
let min_n = bdt_min_nanos();
let max_n = bdt_max_nanos();
if n < min_n {
Extended::NegInf
} else if n > max_n {
Extended::PosInf
} else {
Extended::Finite(Epoch::from_bdt_duration(HD::from_total_nanoseconds(n)))
}
}
crate::conn_l! {
pub EBDTNANO : Extended<Epoch> => i128 {
ceil: ebdtnano_ceil,
inner: ebdtnano_inner,
}
}
#[inline]
fn epoch_to_bdt_f64(e: Epoch) -> f64 {
e.to_duration_in_time_scale(TimeScale::BDT).to_seconds()
}
def_walk_helpers!(
f64_ebdt_walks,
f64,
Epoch,
shift_epoch_tai,
epoch_to_bdt_f64,
epoch_to_ns,
epoch_from_ns
);
fn f064ebdt_ceil(x: F064) -> Extended<Epoch> {
let v = x.into_inner();
if v.is_nan() {
return Extended::PosInf;
}
if v == f64::INFINITY {
return Extended::PosInf;
}
if v == f64::NEG_INFINITY {
return Extended::NegInf;
}
let max_secs = bdt_max_secs_f64();
let min_secs = bdt_min_secs_f64();
if v > max_secs {
return Extended::PosInf;
}
if v <= min_secs {
return Extended::Finite(Epoch::from_tai_duration(HD::MIN));
}
let est = Epoch::from_bdt_seconds(v);
let (z, _) = f64_ebdt_walks::solve_to_ceil(est, v);
Extended::Finite(z)
}
fn f064ebdt_inner(e: Extended<Epoch>) -> F064 {
match e {
Extended::NegInf => N5::new(f64::NEG_INFINITY),
Extended::Finite(e) => N5::new(epoch_to_bdt_f64(e)),
Extended::PosInf => N5::new(f64::INFINITY),
}
}
crate::conn_l! {
pub F064EBDT : F064 => Extended<Epoch> {
ceil: f064ebdt_ceil,
inner: f064ebdt_inner,
}
}
use hifitime::J2000_REF_EPOCH;
#[inline]
fn j2000_tai_ns() -> i128 {
J2000_REF_EPOCH.to_tai_duration().total_nanoseconds()
}
const TT_OFFSET_NS: i128 = 32_184_000_000;
#[inline]
fn tt_min_nanos() -> i128 {
hd_min_nanos()
}
#[inline]
fn tt_max_nanos() -> i128 {
hd_max_nanos() - TT_OFFSET_NS
}
#[inline]
fn tt_min_secs_f64() -> f64 {
(tt_min_nanos() / 1_000_000_000) as f64
}
#[inline]
fn tt_max_secs_f64() -> f64 {
(tt_max_nanos() / 1_000_000_000) as f64
}
#[inline]
fn et_min_secs_f64() -> f64 {
(hd_min_nanos() / 1_000_000_000) as f64
}
#[inline]
fn et_max_secs_f64() -> f64 {
((hd_max_nanos() - j2000_tai_ns()) / 1_000_000_000) as f64
}
#[inline]
fn tdb_min_secs_f64() -> f64 {
et_min_secs_f64()
}
#[inline]
fn tdb_max_secs_f64() -> f64 {
et_max_secs_f64()
}
#[inline]
fn epoch_to_tt_f64(e: Epoch) -> f64 {
e.to_tt_seconds()
}
def_walk_helpers!(
f64_etdt_walks,
f64,
Epoch,
shift_epoch_tai,
epoch_to_tt_f64,
epoch_to_ns,
epoch_from_ns
);
fn f064etdt_ceil(x: F064) -> Extended<Epoch> {
let v = x.into_inner();
if v.is_nan() {
return Extended::PosInf;
}
if v == f64::INFINITY {
return Extended::PosInf;
}
if v == f64::NEG_INFINITY {
return Extended::NegInf;
}
let max_secs = tt_max_secs_f64();
let min_secs = tt_min_secs_f64();
if v > max_secs {
return Extended::PosInf;
}
if v <= min_secs {
return Extended::Finite(Epoch::from_tai_duration(HD::MIN));
}
let est = Epoch::from_tt_seconds(v);
let (z, _) = f64_etdt_walks::solve_to_ceil(est, v);
Extended::Finite(z)
}
fn f064etdt_inner(e: Extended<Epoch>) -> F064 {
match e {
Extended::NegInf => N5::new(f64::NEG_INFINITY),
Extended::Finite(e) => N5::new(e.to_tt_seconds()),
Extended::PosInf => N5::new(f64::INFINITY),
}
}
crate::conn_l! {
pub F064ETDT : F064 => Extended<Epoch> {
ceil: f064etdt_ceil,
inner: f064etdt_inner,
}
}
#[cfg(kani)]
pub(crate) fn f64_etdt_ceil_walk_steps_for_proof(v: f64) -> (Epoch, u32) {
let est = Epoch::from_tt_seconds(v);
let est_widen = est.to_tt_seconds();
if est_widen >= v {
f64_etdt_walks::descend_to_ceil(est, v)
} else {
f64_etdt_walks::ascend_to_ceil(est, v)
}
}
#[cfg(kani)]
pub(crate) fn f64_etdt_ceil_solve_steps_for_proof(v: f64) -> (Epoch, u32) {
let est = Epoch::from_tt_seconds(v);
f64_etdt_walks::solve_to_ceil(est, v)
}
#[inline]
fn epoch_to_et_f64(e: Epoch) -> f64 {
e.to_et_seconds()
}
def_walk_helpers!(
f64_etde_walks,
f64,
Epoch,
shift_epoch_tai,
epoch_to_et_f64,
epoch_to_ns,
epoch_from_ns
);
fn f064etde_ceil(x: F064) -> Extended<Epoch> {
let v = x.into_inner();
if v.is_nan() {
return Extended::PosInf;
}
if v == f64::INFINITY {
return Extended::PosInf;
}
if v == f64::NEG_INFINITY {
return Extended::NegInf;
}
let max_secs = et_max_secs_f64();
let min_secs = et_min_secs_f64();
if v > max_secs {
return Extended::PosInf;
}
if v <= min_secs {
return Extended::Finite(Epoch::from_tai_duration(HD::MIN));
}
let est = Epoch::from_et_seconds(v);
let (z, _) = f64_etde_walks::solve_to_ceil(est, v);
Extended::Finite(z)
}
fn f064etde_inner(e: Extended<Epoch>) -> F064 {
match e {
Extended::NegInf => N5::new(f64::NEG_INFINITY),
Extended::Finite(e) => N5::new(e.to_et_seconds()),
Extended::PosInf => N5::new(f64::INFINITY),
}
}
crate::conn_l! {
pub F064ETDE : F064 => Extended<Epoch> {
ceil: f064etde_ceil,
inner: f064etde_inner,
}
}
#[inline]
fn epoch_to_tdb_f64(e: Epoch) -> f64 {
e.to_tdb_seconds()
}
def_walk_helpers!(
f64_etdb_walks,
f64,
Epoch,
shift_epoch_tai,
epoch_to_tdb_f64,
epoch_to_ns,
epoch_from_ns
);
fn f064etdb_ceil(x: F064) -> Extended<Epoch> {
let v = x.into_inner();
if v.is_nan() {
return Extended::PosInf;
}
if v == f64::INFINITY {
return Extended::PosInf;
}
if v == f64::NEG_INFINITY {
return Extended::NegInf;
}
let max_secs = tdb_max_secs_f64();
let min_secs = tdb_min_secs_f64();
if v > max_secs {
return Extended::PosInf;
}
if v <= min_secs {
return Extended::Finite(Epoch::from_tai_duration(HD::MIN));
}
let est = Epoch::from_tdb_seconds(v);
let (z, _) = f64_etdb_walks::solve_to_ceil(est, v);
Extended::Finite(z)
}
fn f064etdb_inner(e: Extended<Epoch>) -> F064 {
match e {
Extended::NegInf => N5::new(f64::NEG_INFINITY),
Extended::Finite(e) => N5::new(e.to_tdb_seconds()),
Extended::PosInf => N5::new(f64::INFINITY),
}
}
crate::conn_l! {
pub F064ETDB : F064 => Extended<Epoch> {
ceil: f064etdb_ceil,
inner: f064etdb_inner,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[allow(unused_imports)]
use crate::conn::{ConnL, ConnR};
use crate::prop::arb::{
arb_extended_hifi_epoch, arb_extended_hifi_epoch_bounded_f64, arb_hifi_bdt_nanos_in_range,
arb_hifi_epoch, arb_hifi_gpst_nanos_in_range, arb_hifi_gst_nanos_in_range,
arb_hifi_qzsst_nanos_in_range, arb_hifi_tai_nanos_in_range, arb_hifi_unix_nanos_in_range,
extended_float_f64,
};
use crate::prop::{conn as conn_laws, lattice as lattice_laws};
use proptest::prelude::*;
mod hifi_epoch_preorder {
use super::*;
#[allow(unused_imports)]
use crate::conn::{ConnL, ConnR};
proptest! {
#[test]
fn reflexive(x in arb_hifi_epoch()) {
prop_assert!(lattice_laws::lattice_reflexive(&x));
}
#[test]
fn transitive(x in arb_hifi_epoch(), y in arb_hifi_epoch(), z in arb_hifi_epoch()) {
prop_assert!(lattice_laws::lattice_transitive(&x, &y, &z));
}
#[test]
fn antisymmetric(x in arb_hifi_epoch(), y in arb_hifi_epoch()) {
prop_assert!(lattice_laws::lattice_antisymmetric(&x, &y));
}
#[test]
fn bot(x in arb_hifi_epoch()) {
let bot = Epoch::from_tai_duration(HD::MIN);
prop_assert!(lattice_laws::lattice_bot(&bot, &x));
}
#[test]
fn top(x in arb_hifi_epoch()) {
let top = Epoch::from_tai_duration(HD::MAX);
prop_assert!(lattice_laws::lattice_top(&top, &x));
}
}
}
#[test]
fn etaihdur_j1900_zero() {
let j1900 = Epoch::from_tai_duration(HD::ZERO);
assert_eq!(ETAIHDUR.view_l().ceil(j1900), HD::ZERO);
assert_eq!(ETAIHDUR.view_r().floor(j1900), HD::ZERO);
assert_eq!(ETAIHDUR.view_l().upper(HD::ZERO), j1900);
assert_eq!(ETAIHDUR.view_r().lower(HD::ZERO), j1900);
}
#[test]
fn etaihdur_unix_ref_round_trip() {
let unix_dur = UNIX_REF_EPOCH.to_tai_duration();
assert_eq!(ETAIHDUR.view_l().ceil(UNIX_REF_EPOCH), unix_dur);
assert_eq!(
ETAIHDUR.view_l().upper(unix_dur),
Epoch::from_tai_duration(unix_dur),
);
}
#[test]
fn etainano_j1900_zero() {
let j1900 = Epoch::from_tai_duration(HD::ZERO);
assert_eq!(ETAINANO.ceil(Extended::Finite(j1900)), 0_i128);
assert_eq!(ETAINANO.upper(0_i128), Extended::Finite(j1900));
}
#[test]
fn etainano_unix_epoch() {
let unix_in_tai_ns = UNIX_REF_EPOCH.to_tai_duration().total_nanoseconds();
assert_eq!(
ETAINANO.ceil(Extended::Finite(UNIX_REF_EPOCH)),
unix_in_tai_ns,
);
let round_trip = ETAINANO.upper(unix_in_tai_ns);
assert_eq!(round_trip, Extended::Finite(UNIX_REF_EPOCH));
}
#[test]
fn etainano_saturation_extremes() {
assert_eq!(ETAINANO.upper(i128::MAX), Extended::PosInf);
assert_eq!(ETAINANO.upper(i128::MIN), Extended::NegInf);
let max_n = HD::MAX.total_nanoseconds();
assert_eq!(ETAINANO.ceil(Extended::PosInf), max_n + 1);
assert_eq!(ETAINANO.ceil(Extended::NegInf), i128::MIN);
}
#[test]
fn eutchdur_j1900_zero() {
let j1900 = Epoch::from_tai_duration(HD::ZERO);
assert_eq!(EUTCHDUR.view_l().ceil(j1900), HD::ZERO);
assert_eq!(EUTCHDUR.view_r().floor(j1900), HD::ZERO);
let round_trip = EUTCHDUR.view_l().upper(HD::ZERO);
assert_eq!(round_trip, j1900);
}
#[test]
fn eutchdur_unix_ref_round_trip() {
let unix_utc = UNIX_REF_EPOCH.to_utc_duration();
assert_eq!(EUTCHDUR.view_l().ceil(UNIX_REF_EPOCH), unix_utc);
}
#[test]
fn eunxnano_unix_epoch_is_zero() {
assert_eq!(EUNXNANO.ceil(Extended::Finite(UNIX_REF_EPOCH)), 0);
}
#[test]
fn eunxnano_one_second_past_unix() {
let one_sec = Epoch::from_unix_seconds(1.0);
assert_eq!(EUNXNANO.ceil(Extended::Finite(one_sec)), 1_000_000_000_i128,);
}
#[test]
fn eunxnano_y2038_round_trip() {
let y2038_ns: i128 = 2_147_483_648 * 1_000_000_000;
let y2038 = Epoch::from_unix_seconds(2_147_483_648.0);
assert_eq!(EUNXNANO.ceil(Extended::Finite(y2038)), y2038_ns);
assert_eq!(EUNXNANO.upper(y2038_ns), Extended::Finite(y2038));
}
#[test]
fn eunxnano_saturation_extremes() {
assert_eq!(EUNXNANO.upper(i128::MAX), Extended::PosInf);
assert_eq!(EUNXNANO.upper(i128::MIN), Extended::NegInf);
}
#[test]
fn f064etai_zero_is_j1900() {
let zero = N5::new(0.0_f64);
let j1900 = Epoch::from_tai_duration(HD::ZERO);
assert_eq!(F064ETAI.ceil(zero), Extended::Finite(j1900));
assert_eq!(F064ETAI.upper(Extended::Finite(j1900)), zero);
}
#[test]
fn f064etai_half_second() {
let half = N5::new(0.5_f64);
let half_e = Epoch::from_tai_duration(HD::from_seconds(0.5));
assert_eq!(F064ETAI.ceil(half), Extended::Finite(half_e));
}
#[test]
fn f064etai_nan_arms() {
assert_eq!(F064ETAI.ceil(N5::new(f64::NAN)), Extended::PosInf,);
}
#[test]
fn f064etai_inf_arms() {
assert_eq!(F064ETAI.ceil(N5::new(f64::INFINITY)), Extended::PosInf,);
assert_eq!(F064ETAI.ceil(N5::new(f64::NEG_INFINITY)), Extended::NegInf,);
}
#[test]
fn f064etai_extended_bounds_upper_to_infinities() {
assert_eq!(F064ETAI.ceil(N5::new(f64::NEG_INFINITY)), Extended::NegInf);
assert_eq!(F064ETAI.ceil(N5::new(f64::INFINITY)), Extended::PosInf);
assert_eq!(F064ETAI.upper(Extended::NegInf), N5::new(f64::NEG_INFINITY));
assert_eq!(F064ETAI.upper(Extended::PosInf), N5::new(f64::INFINITY));
}
#[test]
fn f064etai_min_secs_fast_path() {
let v_min = N5::new(hd_min_secs_f64());
assert_eq!(
F064ETAI.ceil(v_min),
Extended::Finite(Epoch::from_tai_duration(HD::MIN)),
);
}
#[test]
fn unix_min_secs_f64_equals_hd_min_secs_f64() {
assert_eq!(unix_min_secs_f64(), hd_min_secs_f64());
}
#[test]
fn f064eunx_below_hd_min_secs_collapses_to_hd_min() {
let v = N5::new(hd_min_secs_f64() - 1.0);
assert_eq!(
F064EUNX.ceil(v),
Extended::Finite(Epoch::from_tai_duration(HD::MIN)),
);
}
#[test]
fn f064eunx_zero_is_unix_epoch() {
let zero = N5::new(0.0_f64);
let unix_epoch = Epoch::from_unix_seconds(0.0);
assert_eq!(F064EUNX.ceil(zero), Extended::Finite(unix_epoch));
assert_eq!(F064EUNX.upper(Extended::Finite(unix_epoch)), zero);
}
#[test]
fn f064eunx_one_second() {
let one = N5::new(1.0_f64);
let one_e = Epoch::from_unix_seconds(1.0);
assert_eq!(F064EUNX.ceil(one), Extended::Finite(one_e));
}
#[test]
fn f064eunx_nan_inf_bounds() {
assert_eq!(F064EUNX.ceil(N5::new(f64::NAN)), Extended::PosInf,);
assert_eq!(F064EUNX.ceil(N5::new(f64::INFINITY)), Extended::PosInf,);
assert_eq!(F064EUNX.ceil(N5::new(f64::NEG_INFINITY)), Extended::NegInf);
}
crate::law_battery! {
mod etaihdur_laws,
conn: ETAIHDUR,
fine: arb_hifi_epoch(),
coarse: crate::prop::arb::arb_hifi_duration(),
subset: iso_only,
}
crate::law_battery! {
mod eutchdur_laws,
conn: EUTCHDUR,
fine: arb_hifi_epoch(),
coarse: crate::prop::arb::arb_hifi_duration(),
subset: iso_only,
}
proptest! {
#[test]
fn etainano_galois_l(e in arb_extended_hifi_epoch(), b in any::<i128>()) {
prop_assert!(conn_laws::galois_l(&ETAINANO, e, b));
}
#[test]
fn etainano_closure_l(e in arb_extended_hifi_epoch()) {
prop_assert!(conn_laws::closure_l(&ETAINANO, e));
}
#[test]
fn etainano_kernel_l(b in any::<i128>()) {
prop_assert!(conn_laws::kernel_l(&ETAINANO, b));
}
#[test]
fn etainano_monotone_l(a in arb_extended_hifi_epoch(),
b in arb_extended_hifi_epoch()) {
prop_assert!(conn_laws::monotone_l(&ETAINANO, a, b));
}
#[test]
fn etainano_idempotent(e in arb_extended_hifi_epoch()) {
prop_assert!(conn_laws::idempotent(&ETAINANO, e));
}
#[test]
fn etainano_roundtrip_ceil(b in arb_hifi_tai_nanos_in_range()) {
prop_assert!(conn_laws::roundtrip_ceil(&ETAINANO, b));
}
#[test]
fn eunxnano_galois_l(e in arb_extended_hifi_epoch(), b in any::<i128>()) {
prop_assert!(conn_laws::galois_l(&EUNXNANO, e, b));
}
#[test]
fn eunxnano_closure_l(e in arb_extended_hifi_epoch()) {
prop_assert!(conn_laws::closure_l(&EUNXNANO, e));
}
#[test]
fn eunxnano_kernel_l(b in any::<i128>()) {
prop_assert!(conn_laws::kernel_l(&EUNXNANO, b));
}
#[test]
fn eunxnano_monotone_l(a in arb_extended_hifi_epoch(),
b in arb_extended_hifi_epoch()) {
prop_assert!(conn_laws::monotone_l(&EUNXNANO, a, b));
}
#[test]
fn eunxnano_idempotent(e in arb_extended_hifi_epoch()) {
prop_assert!(conn_laws::idempotent(&EUNXNANO, e));
}
#[test]
fn eunxnano_roundtrip_ceil(b in arb_hifi_unix_nanos_in_range()) {
prop_assert!(conn_laws::roundtrip_ceil(&EUNXNANO, b));
}
}
proptest! {
#![proptest_config(ProptestConfig { cases: 64, .. ProptestConfig::default() })]
#[test]
fn f064etai_galois_l(a in extended_float_f64(),
b in arb_extended_hifi_epoch_bounded_f64()) {
prop_assert!(conn_laws::galois_l(&F064ETAI, a, b));
}
#[test]
fn f064etai_closure_l(a in extended_float_f64()) {
prop_assert!(conn_laws::closure_l(&F064ETAI, a));
}
#[test]
fn f064etai_kernel_l(b in arb_extended_hifi_epoch_bounded_f64()) {
prop_assert!(conn_laws::kernel_l(&F064ETAI, b));
}
#[test]
fn f064etai_monotone_l(a1 in extended_float_f64(),
a2 in extended_float_f64()) {
prop_assert!(conn_laws::monotone_l(&F064ETAI, a1, a2));
}
#[test]
fn f064etai_idempotent(a in extended_float_f64()) {
prop_assert!(conn_laws::idempotent_l(&F064ETAI, a));
}
#[test]
fn f064eunx_galois_l(a in extended_float_f64(),
b in arb_extended_hifi_epoch_bounded_f64()) {
prop_assert!(conn_laws::galois_l(&F064EUNX, a, b));
}
#[test]
fn f064eunx_closure_l(a in extended_float_f64()) {
prop_assert!(conn_laws::closure_l(&F064EUNX, a));
}
#[test]
fn f064eunx_kernel_l(b in arb_extended_hifi_epoch_bounded_f64()) {
prop_assert!(conn_laws::kernel_l(&F064EUNX, b));
}
#[test]
fn f064eunx_monotone_l(a1 in extended_float_f64(),
a2 in extended_float_f64()) {
prop_assert!(conn_laws::monotone_l(&F064EUNX, a1, a2));
}
#[test]
fn f064eunx_idempotent(a in extended_float_f64()) {
prop_assert!(conn_laws::idempotent_l(&F064EUNX, a));
}
}
#[test]
fn egpshdur_ref_zero() {
assert_eq!(EGPSHDUR.view_l().ceil(GPST_REF_EPOCH), HD::ZERO);
assert_eq!(EGPSHDUR.view_l().upper(HD::ZERO), GPST_REF_EPOCH);
}
#[test]
fn egpsnano_ref_zero() {
assert_eq!(EGPSNANO.ceil(Extended::Finite(GPST_REF_EPOCH)), 0_i128);
assert_eq!(EGPSNANO.upper(0_i128), Extended::Finite(GPST_REF_EPOCH));
}
#[test]
fn egpsnano_saturation_extremes() {
assert_eq!(EGPSNANO.upper(i128::MAX), Extended::PosInf);
assert_eq!(EGPSNANO.upper(i128::MIN), Extended::NegInf);
assert_eq!(EGPSNANO.ceil(Extended::NegInf), i128::MIN);
let max_n =
HD::MAX.total_nanoseconds() - GPST_REF_EPOCH.to_tai_duration().total_nanoseconds();
assert_eq!(EGPSNANO.ceil(Extended::PosInf), max_n + 1);
}
#[test]
fn f064egps_zero_is_ref() {
let zero = N5::new(0.0_f64);
assert_eq!(F064EGPS.ceil(zero), Extended::Finite(GPST_REF_EPOCH));
}
#[test]
fn f064egps_nan_inf_bounds() {
assert_eq!(F064EGPS.ceil(N5::new(f64::NAN)), Extended::PosInf,);
assert_eq!(F064EGPS.ceil(N5::new(f64::INFINITY)), Extended::PosInf,);
assert_eq!(F064EGPS.ceil(N5::new(f64::NEG_INFINITY)), Extended::NegInf);
}
#[test]
fn eqzshdur_ref_zero() {
assert_eq!(EQZSHDUR.view_l().ceil(QZSST_REF_EPOCH), HD::ZERO);
}
#[test]
fn eqzsnano_ref_zero() {
assert_eq!(EQZSNANO.ceil(Extended::Finite(QZSST_REF_EPOCH)), 0_i128);
}
#[test]
fn eqzsnano_saturation_extremes() {
assert_eq!(EQZSNANO.upper(i128::MAX), Extended::PosInf);
assert_eq!(EQZSNANO.upper(i128::MIN), Extended::NegInf);
assert_eq!(EQZSNANO.ceil(Extended::NegInf), i128::MIN);
let max_n =
HD::MAX.total_nanoseconds() - QZSST_REF_EPOCH.to_tai_duration().total_nanoseconds();
assert_eq!(EQZSNANO.ceil(Extended::PosInf), max_n + 1);
}
#[test]
fn f064eqzs_zero_is_ref() {
let zero = N5::new(0.0_f64);
assert_eq!(F064EQZS.ceil(zero), Extended::Finite(QZSST_REF_EPOCH));
}
#[test]
fn egsthdur_ref_zero() {
assert_eq!(EGSTHDUR.view_l().ceil(GST_REF_EPOCH), HD::ZERO);
}
#[test]
fn egstnano_ref_zero() {
assert_eq!(EGSTNANO.ceil(Extended::Finite(GST_REF_EPOCH)), 0_i128);
}
#[test]
fn egstnano_saturation_extremes() {
assert_eq!(EGSTNANO.upper(i128::MAX), Extended::PosInf);
assert_eq!(EGSTNANO.upper(i128::MIN), Extended::NegInf);
assert_eq!(EGSTNANO.ceil(Extended::NegInf), i128::MIN);
let max_n =
HD::MAX.total_nanoseconds() - GST_REF_EPOCH.to_tai_duration().total_nanoseconds();
assert_eq!(EGSTNANO.ceil(Extended::PosInf), max_n + 1);
}
#[test]
fn f064egst_zero_is_ref() {
let zero = N5::new(0.0_f64);
assert_eq!(F064EGST.ceil(zero), Extended::Finite(GST_REF_EPOCH));
}
#[test]
fn ebdthdur_ref_zero() {
assert_eq!(EBDTHDUR.view_l().ceil(BDT_REF_EPOCH), HD::ZERO);
}
#[test]
fn ebdtnano_ref_zero() {
assert_eq!(EBDTNANO.ceil(Extended::Finite(BDT_REF_EPOCH)), 0_i128);
}
#[test]
fn ebdtnano_saturation_extremes() {
assert_eq!(EBDTNANO.upper(i128::MAX), Extended::PosInf);
assert_eq!(EBDTNANO.upper(i128::MIN), Extended::NegInf);
assert_eq!(EBDTNANO.ceil(Extended::NegInf), i128::MIN);
let max_n =
HD::MAX.total_nanoseconds() - BDT_REF_EPOCH.to_tai_duration().total_nanoseconds();
assert_eq!(EBDTNANO.ceil(Extended::PosInf), max_n + 1);
}
#[test]
fn f064ebdt_zero_is_ref() {
let zero = N5::new(0.0_f64);
assert_eq!(F064EBDT.ceil(zero), Extended::Finite(BDT_REF_EPOCH));
}
#[test]
fn egps_known_offset_at_interior_epoch() {
let e = Epoch::from_tai_seconds(3_000_000_000.0); let gpst_secs = EGPSHDUR.view_l().ceil(e).to_seconds();
let expected = e.to_tai_seconds() - 2_524_953_619.0;
assert!((gpst_secs - expected).abs() < 1e-6);
}
crate::law_battery! {
mod egpshdur_laws,
conn: EGPSHDUR,
fine: arb_hifi_epoch(),
coarse: crate::prop::arb::arb_hifi_duration(),
subset: iso_only,
}
crate::law_battery! {
mod eqzshdur_laws,
conn: EQZSHDUR,
fine: arb_hifi_epoch(),
coarse: crate::prop::arb::arb_hifi_duration(),
subset: iso_only,
}
crate::law_battery! {
mod egsthdur_laws,
conn: EGSTHDUR,
fine: arb_hifi_epoch(),
coarse: crate::prop::arb::arb_hifi_duration(),
subset: iso_only,
}
crate::law_battery! {
mod ebdthdur_laws,
conn: EBDTHDUR,
fine: arb_hifi_epoch(),
coarse: crate::prop::arb::arb_hifi_duration(),
subset: iso_only,
}
proptest! {
#[test]
fn egpsnano_galois_l(e in arb_extended_hifi_epoch(), b in any::<i128>()) {
prop_assert!(conn_laws::galois_l(&EGPSNANO, e, b));
}
#[test]
fn egpsnano_closure_l(e in arb_extended_hifi_epoch()) {
prop_assert!(conn_laws::closure_l(&EGPSNANO, e));
}
#[test]
fn egpsnano_kernel_l(b in any::<i128>()) {
prop_assert!(conn_laws::kernel_l(&EGPSNANO, b));
}
#[test]
fn egpsnano_monotone_l(a in arb_extended_hifi_epoch(),
b in arb_extended_hifi_epoch()) {
prop_assert!(conn_laws::monotone_l(&EGPSNANO, a, b));
}
#[test]
fn egpsnano_idempotent(e in arb_extended_hifi_epoch()) {
prop_assert!(conn_laws::idempotent(&EGPSNANO, e));
}
#[test]
fn egpsnano_roundtrip_ceil(b in arb_hifi_gpst_nanos_in_range()) {
prop_assert!(conn_laws::roundtrip_ceil(&EGPSNANO, b));
}
#[test]
fn eqzsnano_galois_l(e in arb_extended_hifi_epoch(), b in any::<i128>()) {
prop_assert!(conn_laws::galois_l(&EQZSNANO, e, b));
}
#[test]
fn eqzsnano_closure_l(e in arb_extended_hifi_epoch()) {
prop_assert!(conn_laws::closure_l(&EQZSNANO, e));
}
#[test]
fn eqzsnano_kernel_l(b in any::<i128>()) {
prop_assert!(conn_laws::kernel_l(&EQZSNANO, b));
}
#[test]
fn eqzsnano_monotone_l(a in arb_extended_hifi_epoch(),
b in arb_extended_hifi_epoch()) {
prop_assert!(conn_laws::monotone_l(&EQZSNANO, a, b));
}
#[test]
fn eqzsnano_idempotent(e in arb_extended_hifi_epoch()) {
prop_assert!(conn_laws::idempotent(&EQZSNANO, e));
}
#[test]
fn eqzsnano_roundtrip_ceil(b in arb_hifi_qzsst_nanos_in_range()) {
prop_assert!(conn_laws::roundtrip_ceil(&EQZSNANO, b));
}
#[test]
fn egstnano_galois_l(e in arb_extended_hifi_epoch(), b in any::<i128>()) {
prop_assert!(conn_laws::galois_l(&EGSTNANO, e, b));
}
#[test]
fn egstnano_closure_l(e in arb_extended_hifi_epoch()) {
prop_assert!(conn_laws::closure_l(&EGSTNANO, e));
}
#[test]
fn egstnano_kernel_l(b in any::<i128>()) {
prop_assert!(conn_laws::kernel_l(&EGSTNANO, b));
}
#[test]
fn egstnano_monotone_l(a in arb_extended_hifi_epoch(),
b in arb_extended_hifi_epoch()) {
prop_assert!(conn_laws::monotone_l(&EGSTNANO, a, b));
}
#[test]
fn egstnano_idempotent(e in arb_extended_hifi_epoch()) {
prop_assert!(conn_laws::idempotent(&EGSTNANO, e));
}
#[test]
fn egstnano_roundtrip_ceil(b in arb_hifi_gst_nanos_in_range()) {
prop_assert!(conn_laws::roundtrip_ceil(&EGSTNANO, b));
}
#[test]
fn ebdtnano_galois_l(e in arb_extended_hifi_epoch(), b in any::<i128>()) {
prop_assert!(conn_laws::galois_l(&EBDTNANO, e, b));
}
#[test]
fn ebdtnano_closure_l(e in arb_extended_hifi_epoch()) {
prop_assert!(conn_laws::closure_l(&EBDTNANO, e));
}
#[test]
fn ebdtnano_kernel_l(b in any::<i128>()) {
prop_assert!(conn_laws::kernel_l(&EBDTNANO, b));
}
#[test]
fn ebdtnano_monotone_l(a in arb_extended_hifi_epoch(),
b in arb_extended_hifi_epoch()) {
prop_assert!(conn_laws::monotone_l(&EBDTNANO, a, b));
}
#[test]
fn ebdtnano_idempotent(e in arb_extended_hifi_epoch()) {
prop_assert!(conn_laws::idempotent(&EBDTNANO, e));
}
#[test]
fn ebdtnano_roundtrip_ceil(b in arb_hifi_bdt_nanos_in_range()) {
prop_assert!(conn_laws::roundtrip_ceil(&EBDTNANO, b));
}
#[test]
fn egpsnano_eq_eqzsnano(e in arb_extended_hifi_epoch()) {
prop_assert_eq!(EGPSNANO.ceil(e), EQZSNANO.ceil(e));
}
#[test]
fn egpshdur_eq_eqzshdur(e in arb_hifi_epoch()) {
prop_assert_eq!(EGPSHDUR.view_l().ceil(e), EQZSHDUR.view_l().ceil(e));
}
}
proptest! {
#![proptest_config(ProptestConfig { cases: 64, .. ProptestConfig::default() })]
#[test]
fn f064egps_galois_l(a in extended_float_f64(),
b in arb_extended_hifi_epoch_bounded_f64()) {
prop_assert!(conn_laws::galois_l(&F064EGPS, a, b));
}
#[test]
fn f064egps_closure_l(a in extended_float_f64()) {
prop_assert!(conn_laws::closure_l(&F064EGPS, a));
}
#[test]
fn f064egps_kernel_l(b in arb_extended_hifi_epoch_bounded_f64()) {
prop_assert!(conn_laws::kernel_l(&F064EGPS, b));
}
#[test]
fn f064egps_monotone_l(a1 in extended_float_f64(),
a2 in extended_float_f64()) {
prop_assert!(conn_laws::monotone_l(&F064EGPS, a1, a2));
}
#[test]
fn f064egps_idempotent(a in extended_float_f64()) {
prop_assert!(conn_laws::idempotent_l(&F064EGPS, a));
}
#[test]
fn f064eqzs_galois_l(a in extended_float_f64(),
b in arb_extended_hifi_epoch_bounded_f64()) {
prop_assert!(conn_laws::galois_l(&F064EQZS, a, b));
}
#[test]
fn f064eqzs_closure_l(a in extended_float_f64()) {
prop_assert!(conn_laws::closure_l(&F064EQZS, a));
}
#[test]
fn f064eqzs_kernel_l(b in arb_extended_hifi_epoch_bounded_f64()) {
prop_assert!(conn_laws::kernel_l(&F064EQZS, b));
}
#[test]
fn f064eqzs_monotone_l(a1 in extended_float_f64(),
a2 in extended_float_f64()) {
prop_assert!(conn_laws::monotone_l(&F064EQZS, a1, a2));
}
#[test]
fn f064eqzs_idempotent(a in extended_float_f64()) {
prop_assert!(conn_laws::idempotent_l(&F064EQZS, a));
}
#[test]
fn f064egst_galois_l(a in extended_float_f64(),
b in arb_extended_hifi_epoch_bounded_f64()) {
prop_assert!(conn_laws::galois_l(&F064EGST, a, b));
}
#[test]
fn f064egst_closure_l(a in extended_float_f64()) {
prop_assert!(conn_laws::closure_l(&F064EGST, a));
}
#[test]
fn f064egst_kernel_l(b in arb_extended_hifi_epoch_bounded_f64()) {
prop_assert!(conn_laws::kernel_l(&F064EGST, b));
}
#[test]
fn f064egst_monotone_l(a1 in extended_float_f64(),
a2 in extended_float_f64()) {
prop_assert!(conn_laws::monotone_l(&F064EGST, a1, a2));
}
#[test]
fn f064egst_idempotent(a in extended_float_f64()) {
prop_assert!(conn_laws::idempotent_l(&F064EGST, a));
}
#[test]
fn f064ebdt_galois_l(a in extended_float_f64(),
b in arb_extended_hifi_epoch_bounded_f64()) {
prop_assert!(conn_laws::galois_l(&F064EBDT, a, b));
}
#[test]
fn f064ebdt_closure_l(a in extended_float_f64()) {
prop_assert!(conn_laws::closure_l(&F064EBDT, a));
}
#[test]
fn f064ebdt_kernel_l(b in arb_extended_hifi_epoch_bounded_f64()) {
prop_assert!(conn_laws::kernel_l(&F064EBDT, b));
}
#[test]
fn f064ebdt_monotone_l(a1 in extended_float_f64(),
a2 in extended_float_f64()) {
prop_assert!(conn_laws::monotone_l(&F064EBDT, a1, a2));
}
#[test]
fn f064ebdt_idempotent(a in extended_float_f64()) {
prop_assert!(conn_laws::idempotent_l(&F064EBDT, a));
}
}
#[test]
fn f064etdt_zero_is_j1900_tt() {
let zero = N5::new(0.0_f64);
let j1900_tt = Epoch::from_tt_duration(HD::ZERO);
assert_eq!(F064ETDT.ceil(zero), Extended::Finite(j1900_tt));
}
#[test]
fn f064etdt_nan_inf_bounds() {
assert_eq!(F064ETDT.ceil(N5::new(f64::NAN)), Extended::PosInf,);
assert_eq!(F064ETDT.ceil(N5::new(f64::INFINITY)), Extended::PosInf,);
assert_eq!(F064ETDT.ceil(N5::new(f64::NEG_INFINITY)), Extended::NegInf);
}
#[test]
fn f064etde_zero_is_near_j2000() {
let zero = N5::new(0.0_f64);
let j2000_et = Epoch::from_et_seconds(0.0);
let result = F064ETDE.ceil(zero);
match result {
Extended::Finite(got) => {
assert!(
(got - j2000_et).abs() < 1.0 * hifitime::Unit::Nanosecond,
"F064ETDE.ceil(0.0) = {got:?}, expected near {j2000_et:?}",
);
}
other => panic!("expected Finite, got {other:?}"),
}
}
#[test]
fn f064etde_nan_inf_bounds() {
assert_eq!(F064ETDE.ceil(N5::new(f64::NAN)), Extended::PosInf,);
assert_eq!(F064ETDE.ceil(N5::new(f64::NEG_INFINITY)), Extended::NegInf);
assert_eq!(F064ETDE.ceil(N5::new(f64::INFINITY)), Extended::PosInf);
}
#[test]
fn f064etdb_zero_is_near_j2000() {
let zero = N5::new(0.0_f64);
let j2000_tdb = Epoch::from_tdb_seconds(0.0);
let result = F064ETDB.ceil(zero);
match result {
Extended::Finite(got) => {
assert!(
(got - j2000_tdb).abs() < 1.0 * hifitime::Unit::Nanosecond,
"F064ETDB.ceil(0.0) = {got:?}, expected near {j2000_tdb:?}",
);
}
other => panic!("expected Finite, got {other:?}"),
}
}
#[test]
fn f064etdb_nan_inf_bounds() {
assert_eq!(F064ETDB.ceil(N5::new(f64::NAN)), Extended::PosInf,);
assert_eq!(F064ETDB.ceil(N5::new(f64::NEG_INFINITY)), Extended::NegInf);
assert_eq!(F064ETDB.ceil(N5::new(f64::INFINITY)), Extended::PosInf);
}
#[test]
fn etdt_known_offset_at_interior_epoch() {
let e = Epoch::from_tai_seconds(3_000_000_000.0);
let tt_secs = e.to_tt_seconds();
let tai_secs = e.to_tai_seconds();
assert!((tt_secs - tai_secs - 32.184).abs() < 1e-6);
}
proptest! {
#![proptest_config(ProptestConfig { cases: 64, .. ProptestConfig::default() })]
#[test]
fn f064etdt_galois_l(a in extended_float_f64(),
b in arb_extended_hifi_epoch_bounded_f64()) {
prop_assert!(conn_laws::galois_l(&F064ETDT, a, b));
}
#[test]
fn f064etdt_closure_l(a in extended_float_f64()) {
prop_assert!(conn_laws::closure_l(&F064ETDT, a));
}
#[test]
fn f064etdt_kernel_l(b in arb_extended_hifi_epoch_bounded_f64()) {
prop_assert!(conn_laws::kernel_l(&F064ETDT, b));
}
#[test]
fn f064etdt_monotone_l(a1 in extended_float_f64(),
a2 in extended_float_f64()) {
prop_assert!(conn_laws::monotone_l(&F064ETDT, a1, a2));
}
#[test]
fn f064etdt_idempotent(a in extended_float_f64()) {
prop_assert!(conn_laws::idempotent_l(&F064ETDT, a));
}
#[test]
fn f064etde_galois_l(a in extended_float_f64(),
b in arb_extended_hifi_epoch_bounded_f64()) {
prop_assert!(conn_laws::galois_l(&F064ETDE, a, b));
}
#[test]
fn f064etde_closure_l(a in extended_float_f64()) {
prop_assert!(conn_laws::closure_l(&F064ETDE, a));
}
#[test]
fn f064etde_kernel_l(b in arb_extended_hifi_epoch_bounded_f64()) {
prop_assert!(conn_laws::kernel_l(&F064ETDE, b));
}
#[test]
fn f064etde_monotone_l(a1 in extended_float_f64(),
a2 in extended_float_f64()) {
prop_assert!(conn_laws::monotone_l(&F064ETDE, a1, a2));
}
#[test]
fn f064etde_idempotent(a in extended_float_f64()) {
prop_assert!(conn_laws::idempotent_l(&F064ETDE, a));
}
#[test]
fn f064etdb_galois_l(a in extended_float_f64(),
b in arb_extended_hifi_epoch_bounded_f64()) {
prop_assert!(conn_laws::galois_l(&F064ETDB, a, b));
}
#[test]
fn f064etdb_closure_l(a in extended_float_f64()) {
prop_assert!(conn_laws::closure_l(&F064ETDB, a));
}
#[test]
fn f064etdb_kernel_l(b in arb_extended_hifi_epoch_bounded_f64()) {
prop_assert!(conn_laws::kernel_l(&F064ETDB, b));
}
#[test]
fn f064etdb_monotone_l(a1 in extended_float_f64(),
a2 in extended_float_f64()) {
prop_assert!(conn_laws::monotone_l(&F064ETDB, a1, a2));
}
#[test]
fn f064etdb_idempotent(a in extended_float_f64()) {
prop_assert!(conn_laws::idempotent_l(&F064ETDB, a));
}
}
#[test]
fn f064etde_at_j2000_within_1ns() {
let j2000_et = Epoch::from_et_seconds(0.0);
let ef = F064ETDE.upper(Extended::Finite(j2000_et));
let recovered = F064ETDE.ceil(ef);
match recovered {
Extended::Finite(got) => {
let drift = (got - j2000_et).abs();
assert!(
drift <= 1.0 * hifitime::Unit::Nanosecond,
"ET round-trip at J2000 diverged: Δ {drift:?}",
);
}
other => panic!("expected Finite, got {other:?}"),
}
}
#[test]
fn f064etdb_at_j2000_within_1ns() {
let j2000_tdb = Epoch::from_tdb_seconds(0.0);
let ef = F064ETDB.upper(Extended::Finite(j2000_tdb));
let recovered = F064ETDB.ceil(ef);
match recovered {
Extended::Finite(got) => {
let drift = (got - j2000_tdb).abs();
assert!(
drift <= 1.0 * hifitime::Unit::Nanosecond,
"TDB round-trip at J2000 diverged: Δ {drift:?}",
);
}
other => panic!("expected Finite, got {other:?}"),
}
}
#[test]
fn f064_etai_solve_terminates_at_walk_pathological_magnitude() {
let v = N5::new(1.0e13_f64);
let _ = F064ETAI.ceil(v);
}
proptest! {
#![proptest_config(ProptestConfig::with_cases(64))]
#[test]
fn f64_etai_solve_matches_walk_in_safe_range(v in -1.0e6_f64..1.0e6_f64) {
let est = Epoch::from_tai_seconds(v);
let est_widen = est.to_tai_seconds();
let (walk_z, _) = if est_widen >= v {
f64_etai_walks::descend_to_ceil(est, v)
} else {
f64_etai_walks::ascend_to_ceil(est, v)
};
let (solve_z, steps) = f64_etai_walks::solve_to_ceil(est, v);
prop_assert_eq!(solve_z, walk_z);
prop_assert!(steps <= 52, "solve_to_ceil took {steps} steps");
}
}
}