Reduce the error when scaling a real time value.
When scaling a time value we would often use the power operator to create constants 10**-N that were then multiplied with the original value. The problem with this is that there is some errors in the representation of the fractional number. It is better to create a integer value 10**N and then divide the original value by this exact constant. You still have the calculation error, but the scale value is now an exactly real value.
This commit is contained in:
parent
5fbffe24cc
commit
ff309fb04f
|
|
@ -248,9 +248,11 @@ static void get_time(char *rtn, const char *value, int prec,
|
|||
static void get_time_real(char *rtn, double value, int prec,
|
||||
PLI_INT32 time_units)
|
||||
{
|
||||
/* Scale the value if its time units differ from the format units. */
|
||||
if (time_units != timeformat_info.units) {
|
||||
/* Scale the value from its time units to the format time units. */
|
||||
if (time_units >= timeformat_info.units) {
|
||||
value *= pow(10.0, time_units - timeformat_info.units);
|
||||
} else {
|
||||
value /= pow(10.0, timeformat_info.units - time_units);
|
||||
}
|
||||
sprintf(rtn, "%0.*f%s", prec, value, timeformat_info.suff);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000-2010 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000-2011 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -95,7 +95,9 @@ static PLI_INT32 sys_realtime_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
|
|||
|
||||
/* For $abstime() we return the time in second. */
|
||||
if (strcmp(name, "$abstime") == 0) {
|
||||
now.real *= pow(10.0, vpi_get(vpiTimeUnit, mod));
|
||||
PLI_INT32 scale = vpi_get(vpiTimeUnit, mod);
|
||||
if (scale >= 0) now.real *= pow(10.0, scale);
|
||||
else now.real /= pow(10.0, -scale);
|
||||
}
|
||||
|
||||
val.format = vpiRealVal;
|
||||
|
|
|
|||
|
|
@ -475,7 +475,7 @@ int vpip_time_precision_from_handle(vpiHandle obj)
|
|||
|
||||
void vpi_get_time(vpiHandle obj, s_vpi_time*vp)
|
||||
{
|
||||
int units;
|
||||
int scale;
|
||||
vvp_time64_t time;
|
||||
|
||||
assert(vp);
|
||||
|
|
@ -489,9 +489,10 @@ void vpi_get_time(vpiHandle obj, s_vpi_time*vp)
|
|||
break;
|
||||
|
||||
case vpiScaledRealTime:
|
||||
units = vpip_time_units_from_handle(obj);
|
||||
vp->real = pow(10.0L, vpip_get_time_precision() - units);
|
||||
vp->real *= time;
|
||||
scale = vpip_get_time_precision() -
|
||||
vpip_time_units_from_handle(obj);
|
||||
if (scale >= 0) vp->real = (double)time * pow(10.0, scale);
|
||||
else vp->real = (double)time / pow(10.0, -scale);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -953,6 +954,7 @@ vpiHandle vpi_put_value(vpiHandle obj, s_vpi_value*vp,
|
|||
|
||||
if (flags!=vpiNoDelay && flags!=vpiForceFlag && flags!=vpiReleaseFlag) {
|
||||
vvp_time64_t dly;
|
||||
int scale;
|
||||
|
||||
if (vpi_get(vpiAutomatic, obj)) {
|
||||
fprintf(stderr, "vpi error: cannot put a value with "
|
||||
|
|
@ -966,10 +968,13 @@ vpiHandle vpi_put_value(vpiHandle obj, s_vpi_value*vp,
|
|||
|
||||
switch (when->type) {
|
||||
case vpiScaledRealTime:
|
||||
dly = (vvp_time64_t)(when->real *
|
||||
(pow(10.0L,
|
||||
vpip_time_units_from_handle(obj) -
|
||||
vpip_get_time_precision())));
|
||||
scale = vpip_time_units_from_handle(obj) -
|
||||
vpip_get_time_precision();
|
||||
if (scale >= 0) {
|
||||
dly = (vvp_time64_t)(when->real * pow(10.0, scale));
|
||||
} else {
|
||||
dly = (vvp_time64_t)(when->real / pow(10.0, -scale));
|
||||
}
|
||||
break;
|
||||
case vpiSimTime:
|
||||
dly = vpip_timestruct_to_time(when);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -55,14 +55,12 @@ vvp_time64_t vpip_timestruct_to_time(const struct t_vpi_time*ts)
|
|||
|
||||
double vpip_time_to_scaled_real(vvp_time64_t ti, struct __vpiScope*scope)
|
||||
{
|
||||
int units;
|
||||
if (scope)
|
||||
units = scope->time_units;
|
||||
else
|
||||
units = vpi_time_precision;
|
||||
double val;
|
||||
int scale = 0;
|
||||
if (scope) scale = vpi_time_precision - scope->time_units;
|
||||
|
||||
double val = pow(10.0L, vpi_time_precision - units);
|
||||
val *= ti;
|
||||
if (scale >= 0) val = (double)ti * pow(10.0, scale);
|
||||
else val = (double)ti / pow(10.0, -scale);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue