From 6da2658fddded3d2f88c53f27f3707be7e910486 Mon Sep 17 00:00:00 2001 From: Rajan Gill Date: Sun, 16 Sep 2018 12:22:36 -0600 Subject: [PATCH] libs/libc/math: Add variable convergence in log() and logf() to avoid hangs caused by failure to converge for very specific input values. --- libs/libc/math/lib_log.c | 37 +++++++++++++++++++++++++++++++++++-- libs/libc/math/lib_logf.c | 27 ++++++++++++++++++++++++++- 2 files changed, 61 insertions(+), 3 deletions(-) diff --git a/libs/libc/math/lib_log.c b/libs/libc/math/lib_log.c index 10c9ccc025..c2d414eb8e 100644 --- a/libs/libc/math/lib_log.c +++ b/libs/libc/math/lib_log.c @@ -3,7 +3,7 @@ * * This file is a part of NuttX: * - * Copyright (C) 2012 Gregory Nutt. All rights reserved. + * Copyright (C) 2012, 2018 Gregory Nutt. All rights reserved. * Ported by: Darcy Gong * * It derives from the Rhombus OS math library by Nick Johnson which has @@ -35,19 +35,44 @@ #include #include +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* To avoid looping forever in particular corner cases, every LOGF_MAX_ITER + * the error criteria is relaxed by a factor LOGF_RELAX_MULTIPLIER. + * todo: might need to adjust the double floating point version too. + */ + +#define LOGF_MAX_ITER 10 +#define LOGF_RELAX_MULTIPLIER 2 + /**************************************************************************** * Public Functions ****************************************************************************/ +/**************************************************************************** + * Name: log + ****************************************************************************/ + #ifdef CONFIG_HAVE_DOUBLE double log(double x) { - double y, y_old, ey, epsilon; + double y; + double y_old; + double ey; + double epsilon; + int relax_factor; + int i; y = 0.0; y_old = 1.0; epsilon = DBL_EPSILON; + i = 0; + relax_factor = 1; + + while (y > y_old + epsilon || y < y_old - epsilon) { y_old = y; @@ -65,6 +90,14 @@ double log(double x) } epsilon = (fabs(y) > 1.0) ? fabs(y) * DBL_EPSILON : DBL_EPSILON; + + if (++i >= LOGF_MAX_ITER) + { + relax_factor *= LOGF_RELAX_MULTIPLIER; + i = 0; + } + + epsilon *= relax_factor; } if (y == 700.0) diff --git a/libs/libc/math/lib_logf.c b/libs/libc/math/lib_logf.c index dc6bcdb5b9..0faaf3b55e 100644 --- a/libs/libc/math/lib_logf.c +++ b/libs/libc/math/lib_logf.c @@ -3,7 +3,7 @@ * * This file is a part of NuttX: * - * Copyright (C) 2012, 2017 Gregory Nutt. All rights reserved. + * Copyright (C) 2012, 2017-2018 Gregory Nutt. All rights reserved. * Ported by: Darcy Gong * * It derives from the Rhombus OS math library by Nick Johnson which has @@ -32,8 +32,20 @@ #include #include +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + #define FLT_MAX_EXP_X 88.0F +/* To avoid looping forever in particular corner cases, every LOGF_MAX_ITER + * the error criteria is relaxed by a factor LOGF_RELAX_MULTIPLIER. + * todo: might need to adjust the double floating point version too. + */ + +#define LOGF_MAX_ITER 10 +#define LOGF_RELAX_MULTIPLIER 2 + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -48,11 +60,16 @@ float logf(float x) float y_old; float ey; float epsilon; + int relax_factor; + int i; y = 0.0F; y_old = 1.0F; epsilon = FLT_EPSILON; + i = 0; + relax_factor = 1; + while (y > y_old + epsilon || y < y_old - epsilon) { y_old = y; @@ -70,6 +87,14 @@ float logf(float x) } epsilon = (fabsf(y) > 1.0F) ? fabsf(y) * FLT_EPSILON : FLT_EPSILON; + + if (++i >= LOGF_MAX_ITER) + { + relax_factor *= LOGF_RELAX_MULTIPLIER; + i = 0; + } + + epsilon *= relax_factor; } if (y == FLT_MAX_EXP_X)