Skip to content
Permalink
Browse files
iio: afe: rescale: fix accuracy for small fractional scales
The approximation caused by integer divisions can be costly on smaller
scale values since the decimal part is significant compared to the
integer part. Switch to an IIO_VAL_INT_PLUS_NANO scale type in such
cases to maintain accuracy.

Signed-off-by: Liam Beguin <lvb@xiphos.com>
  • Loading branch information
Liambeguin authored and intel-lab-lkp committed Aug 20, 2021
1 parent d519d40 commit e5c2e1505fa3f8cf9fe6d3a21f3a5c585efc6dce
Showing 1 changed file with 25 additions and 2 deletions.
@@ -22,7 +22,7 @@ int rescale_process_scale(struct rescale *rescale, int scale_type,
int *val, int *val2)
{
s64 tmp;
s32 rem;
s32 rem, rem2;
u32 mult;
u32 neg;

@@ -38,8 +38,31 @@ int rescale_process_scale(struct rescale *rescale, int scale_type,
tmp = (s64)*val * 1000000000LL;
tmp = div_s64(tmp, rescale->denominator);
tmp *= rescale->numerator;
tmp = div_s64(tmp, 1000000000LL);

tmp = div_s64_rem(tmp, 1000000000LL, &rem);
*val = tmp;

/*
* For small values, the approximation can be costly,
* change scale type to maintain accuracy.
*
* 100 vs. 10000000 NANO caps the error to about 100 ppm.
*/
if (scale_type == IIO_VAL_FRACTIONAL)
tmp = *val2;
else
tmp = 1 << *val2;

if (abs(rem) > 10000000 && abs(*val / tmp) < 100) {
*val = div_s64_rem(*val, tmp, &rem2);

*val2 = div_s64(rem, tmp);
if (rem2)
*val2 += div_s64(rem2 * 1000000000LL, tmp);

return IIO_VAL_INT_PLUS_NANO;
}

return scale_type;
case IIO_VAL_INT_PLUS_NANO:
case IIO_VAL_INT_PLUS_MICRO:

0 comments on commit e5c2e15

Please sign in to comment.