Fix floating overflow in tpl_model
Add bounded_exp()
BUG=aomedia:3058
Change-Id: I419ce9064cc857a718c8909fc997ca0ac521e001
diff --git a/av1/encoder/tpl_model.c b/av1/encoder/tpl_model.c
index baa2e3f..aebb9a8 100644
--- a/av1/encoder/tpl_model.c
+++ b/av1/encoder/tpl_model.c
@@ -35,6 +35,18 @@
#include "av1/encoder/reconinter_enc.h"
#include "av1/encoder/tpl_model.h"
+static INLINE double exp_bounded(double v) {
+ // When v > 700 or <-700, the exp function will be close to overflow
+ // For details, see the "Notes" in the following link.
+ // https://en.cppreference.com/w/c/numeric/math/exp
+ if (v > 700) {
+ return DBL_MAX;
+ } else if (v < -700) {
+ return 0;
+ }
+ return exp(v);
+}
+
void av1_init_tpl_txfm_stats(TplTxfmStats *tpl_txfm_stats) {
tpl_txfm_stats->coeff_num = 256;
tpl_txfm_stats->txfm_block_count = 0;
@@ -1739,7 +1751,7 @@
const double scaling_factor = (double)new_rdmult / (double)orig_rdmult;
double scale_adj = log(scaling_factor) - log_sum / base_block_count;
- scale_adj = exp(scale_adj);
+ scale_adj = exp_bounded(scale_adj);
for (row = mi_row / num_mi_w;
row < num_rows && row < mi_row / num_mi_w + num_brows; ++row) {
@@ -1754,7 +1766,7 @@
double av1_exponential_entropy(double q_step, double b) {
b = AOMMAX(b, TPL_EPSILON);
- double z = fmax(exp(-q_step / b), TPL_EPSILON);
+ double z = fmax(exp_bounded(-q_step / b), TPL_EPSILON);
return -log2(1 - z) - z * log2(z) / (1 - z);
}
@@ -1762,7 +1774,7 @@
// zero bin's size is zero_bin_ratio * q_step
// non-zero bin's size is q_step
b = AOMMAX(b, TPL_EPSILON);
- double z = fmax(exp(-zero_bin_ratio / 2 * q_step / b), TPL_EPSILON);
+ double z = fmax(exp_bounded(-zero_bin_ratio / 2 * q_step / b), TPL_EPSILON);
double h = av1_exponential_entropy(q_step, b);
double r = -(1 - z) * log2(1 - z) - z * log2(z) + z * (h + 1);
return r;
@@ -1812,12 +1824,12 @@
double zero_bin_ratio, int qcoeff) {
b = AOMMAX(b, TPL_EPSILON);
int abs_qcoeff = abs(qcoeff);
- double z0 = fmax(exp(-zero_bin_ratio / 2 * q_step / b), TPL_EPSILON);
+ double z0 = fmax(exp_bounded(-zero_bin_ratio / 2 * q_step / b), TPL_EPSILON);
if (abs_qcoeff == 0) {
double r = -log2(1 - z0);
return r;
} else {
- double z = fmax(exp(-q_step / b), TPL_EPSILON);
+ double z = fmax(exp_bounded(-q_step / b), TPL_EPSILON);
double r = 1 - log2(z0) - log2(1 - z) - (abs_qcoeff - 1) * log2(z);
return r;
}