lib: timeutil: fix conversion drift
Fix conversion drifts for large deltas by only applying float operations when the skew requires it. This helps because not all integers are representable as floats, so large integers are neccessarily quantised when performing float operations. When required, floating-point operations are now performed on doubles instead of floats. Fixes #37263. Signed-off-by: Jordan Yates <jordan.yates@data61.csiro.au>
This commit is contained in:
parent
d2363be091
commit
2c1f184d02
1 changed files with 18 additions and 7 deletions
|
@ -28,8 +28,8 @@
|
||||||
* @see http://howardhinnant.github.io/date_algorithms.html#days_from_civil
|
* @see http://howardhinnant.github.io/date_algorithms.html#days_from_civil
|
||||||
*/
|
*/
|
||||||
static int64_t time_days_from_civil(int64_t y,
|
static int64_t time_days_from_civil(int64_t y,
|
||||||
unsigned int m,
|
unsigned int m,
|
||||||
unsigned int d)
|
unsigned int d)
|
||||||
{
|
{
|
||||||
y -= m <= 2;
|
y -= m <= 2;
|
||||||
|
|
||||||
|
@ -134,8 +134,13 @@ int timeutil_sync_ref_from_local(const struct timeutil_sync_state *tsp,
|
||||||
if ((tsp->skew > 0) && (tsp->base.ref > 0) && (refp != NULL)) {
|
if ((tsp->skew > 0) && (tsp->base.ref > 0) && (refp != NULL)) {
|
||||||
const struct timeutil_sync_config *cfg = tsp->cfg;
|
const struct timeutil_sync_config *cfg = tsp->cfg;
|
||||||
int64_t local_delta = local - tsp->base.local;
|
int64_t local_delta = local - tsp->base.local;
|
||||||
int64_t ref_delta = (int64_t)(tsp->skew * local_delta) *
|
/* (x * 1.0) != x for large values of x.
|
||||||
cfg->ref_Hz / cfg->local_Hz;
|
* Therefore only apply the multiplication if the skew is not one.
|
||||||
|
*/
|
||||||
|
if (tsp->skew != 1.0) {
|
||||||
|
local_delta *= (double)tsp->skew;
|
||||||
|
}
|
||||||
|
int64_t ref_delta = local_delta * cfg->ref_Hz / cfg->local_Hz;
|
||||||
int64_t ref_abs = (int64_t)tsp->base.ref + ref_delta;
|
int64_t ref_abs = (int64_t)tsp->base.ref + ref_delta;
|
||||||
|
|
||||||
if (ref_abs < 0) {
|
if (ref_abs < 0) {
|
||||||
|
@ -157,10 +162,16 @@ int timeutil_sync_local_from_ref(const struct timeutil_sync_state *tsp,
|
||||||
if ((tsp->skew > 0) && (tsp->base.ref > 0) && (localp != NULL)) {
|
if ((tsp->skew > 0) && (tsp->base.ref > 0) && (localp != NULL)) {
|
||||||
const struct timeutil_sync_config *cfg = tsp->cfg;
|
const struct timeutil_sync_config *cfg = tsp->cfg;
|
||||||
int64_t ref_delta = (int64_t)(ref - tsp->base.ref);
|
int64_t ref_delta = (int64_t)(ref - tsp->base.ref);
|
||||||
double local_delta = (ref_delta * cfg->local_Hz) / cfg->ref_Hz
|
/* (x / 1.0) != x for large values of x.
|
||||||
/ tsp->skew;
|
* Therefore only apply the division if the skew is not one.
|
||||||
|
*/
|
||||||
|
int64_t local_delta = (ref_delta * cfg->local_Hz) / cfg->ref_Hz;
|
||||||
|
|
||||||
|
if (tsp->skew != 1.0) {
|
||||||
|
local_delta /= (double)tsp->skew;
|
||||||
|
}
|
||||||
int64_t local_abs = (int64_t)tsp->base.local
|
int64_t local_abs = (int64_t)tsp->base.local
|
||||||
+ (int64_t)local_delta;
|
+ (int64_t)local_delta;
|
||||||
|
|
||||||
*localp = local_abs;
|
*localp = local_abs;
|
||||||
rv = (int)(tsp->skew != 1.0);
|
rv = (int)(tsp->skew != 1.0);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue