use type promotion only where necessary

This commit is contained in:
conrad
2025-08-07 16:02:57 +10:00
parent fa4b928937
commit 0c8e97e10e
+118 -89
View File
@@ -40,9 +40,7 @@ op_norm::vec_norm_1(const Proxy<T1>& P, const typename arma_not_cx<typename T1::
typedef typename T1::elem_type eT;
typedef typename conditional_promote_type<is_real_or_cx<eT>::value, eT, float>::result acc_eT;
acc_eT acc = acc_eT(0);
eT acc = eT(0);
if(Proxy<T1>::use_at == false)
{
@@ -50,22 +48,22 @@ op_norm::vec_norm_1(const Proxy<T1>& P, const typename arma_not_cx<typename T1::
const uword N = P.get_n_elem();
acc_eT acc1 = acc_eT(0);
acc_eT acc2 = acc_eT(0);
eT acc1 = eT(0);
eT acc2 = eT(0);
uword i,j;
for(i=0, j=1; j<N; i+=2, j+=2)
{
acc1 += std::abs(acc_eT(A[i]));
acc2 += std::abs(acc_eT(A[j]));
acc1 += std::abs(A[i]);
acc2 += std::abs(A[j]);
}
if(i < N)
{
acc1 += std::abs(acc_eT(A[i]));
acc1 += std::abs(A[i]);
}
acc = acc1 + acc2;
acc = (acc1 + acc2);
}
else
{
@@ -76,13 +74,13 @@ op_norm::vec_norm_1(const Proxy<T1>& P, const typename arma_not_cx<typename T1::
{
for(uword col=0; col<n_cols; ++col)
{
acc += std::abs(acc_eT(P.at(0,col)));
acc += std::abs(P.at(0,col));
}
}
else
{
acc_eT acc1 = acc_eT(0);
acc_eT acc2 = acc_eT(0);
eT acc1 = eT(0);
eT acc2 = eT(0);
for(uword col=0; col<n_cols; ++col)
{
@@ -90,21 +88,21 @@ op_norm::vec_norm_1(const Proxy<T1>& P, const typename arma_not_cx<typename T1::
for(i=0, j=1; j<n_rows; i+=2, j+=2)
{
acc1 += std::abs(acc_eT(P.at(i,col)));
acc2 += std::abs(acc_eT(P.at(j,col)));
acc1 += std::abs(P.at(i,col));
acc2 += std::abs(P.at(j,col));
}
if(i < n_rows)
{
acc1 += std::abs(acc_eT(P.at(i,col)));
acc1 += std::abs(P.at(i,col));
}
}
acc = acc1 + acc2;
acc = (acc1 + acc2);
}
}
return eT(acc);
return acc;
}
@@ -120,11 +118,7 @@ op_norm::vec_norm_1(const Proxy<T1>& P, const typename arma_cx_only<typename T1:
typedef typename T1::elem_type eT;
typedef typename T1::pod_type T;
typedef typename conditional_promote_type<is_real_or_cx<eT>::value, eT, float>::result acc_eT;
typedef typename get_pod_type<acc_eT>::result acc_T;
acc_T acc = acc_T(0);
T acc = T(0);
if(Proxy<T1>::use_at == false)
{
@@ -139,7 +133,7 @@ op_norm::vec_norm_1(const Proxy<T1>& P, const typename arma_cx_only<typename T1:
const T a = X.real();
const T b = X.imag();
acc += std::sqrt( acc_T(a*a) + acc_T(b*b) );
acc += std::sqrt( (a*a) + (b*b) );
}
}
else
@@ -156,7 +150,7 @@ op_norm::vec_norm_1(const Proxy<T1>& P, const typename arma_cx_only<typename T1:
const T a = X.real();
const T b = X.imag();
acc += std::sqrt( acc_T(a*a) + acc_T(b*b) );
acc += std::sqrt( (a*a) + (b*b) );
}
}
else
@@ -169,19 +163,23 @@ op_norm::vec_norm_1(const Proxy<T1>& P, const typename arma_cx_only<typename T1:
const T a = X.real();
const T b = X.imag();
acc += std::sqrt( acc_T(a*a) + acc_T(b*b) );
acc += std::sqrt( (a*a) + (b*b) );
}
}
}
if( (acc != acc_T(0)) && arma_isfinite(acc) )
if( (acc != T(0)) && arma_isfinite(acc) )
{
return T(acc);
return acc;
}
else
{
arma_debug_print("detected possible underflow or overflow");
typedef typename promote_type<eT, float>::result acc_eT;
typedef typename get_pod_type<acc_eT>::result acc_T;
const quasi_unwrap<typename Proxy<T1>::stored_type> R(P.Q);
const uword N = R.M.n_elem;
@@ -232,7 +230,7 @@ op_norm::vec_norm_1_direct_std(const Mat<eT>& X, const typename arma_blas_real_o
const eT* A = X.memptr();
eT out_val = eT(0);
#if defined(ARMA_USE_ATLAS)
{
arma_debug_print("atlas::cblas_asum()");
@@ -287,36 +285,34 @@ op_norm::vec_norm_1_direct_mem(const uword N, const eT* A)
{
arma_debug_sigprint();
typedef typename conditional_promote_type<is_real_or_cx<eT>::value, eT, float>::result acc_eT;
#if (defined(ARMA_SIMPLE_LOOPS) || defined(__FAST_MATH__))
{
acc_eT acc1 = acc_eT(0);
eT acc1 = eT(0);
if(memory::is_aligned(A))
{
memory::mark_as_aligned(A);
for(uword i=0; i<N; ++i) { acc1 += std::abs(acc_eT(A[i])); }
for(uword i=0; i<N; ++i) { acc1 += std::abs(A[i]); }
}
else
{
for(uword i=0; i<N; ++i) { acc1 += std::abs(acc_eT(A[i])); }
for(uword i=0; i<N; ++i) { acc1 += std::abs(A[i]); }
}
return eT(acc1);
return acc1;
}
#else
{
acc_eT acc1 = acc_eT(0);
acc_eT acc2 = acc_eT(0);
eT acc1 = eT(0);
eT acc2 = eT(0);
uword j;
for(j=1; j<N; j+=2)
{
const acc_eT tmp_i = acc_eT(*A); A++;
const acc_eT tmp_j = acc_eT(*A); A++;
const eT tmp_i = (*A); A++;
const eT tmp_j = (*A); A++;
acc1 += std::abs(tmp_i);
acc2 += std::abs(tmp_j);
@@ -324,10 +320,10 @@ op_norm::vec_norm_1_direct_mem(const uword N, const eT* A)
if((j-1) < N)
{
acc1 += std::abs(acc_eT(*A));
acc1 += std::abs(*A);
}
return eT(acc1 + acc2);
return (acc1 + acc2);
}
#endif
}
@@ -353,9 +349,7 @@ op_norm::vec_norm_2(const Proxy<T1>& P, const typename arma_not_cx<typename T1::
typedef typename T1::elem_type eT;
typedef typename conditional_promote_type<is_real_or_cx<eT>::value, eT, float>::result acc_eT;
acc_eT acc = acc_eT(0);
eT acc = eT(0);
if(Proxy<T1>::use_at == false)
{
@@ -363,8 +357,8 @@ op_norm::vec_norm_2(const Proxy<T1>& P, const typename arma_not_cx<typename T1::
const uword N = P.get_n_elem();
acc_eT acc1 = acc_eT(0);
acc_eT acc2 = acc_eT(0);
eT acc1 = eT(0);
eT acc2 = eT(0);
uword i,j;
@@ -373,18 +367,18 @@ op_norm::vec_norm_2(const Proxy<T1>& P, const typename arma_not_cx<typename T1::
const eT tmp_i = A[i];
const eT tmp_j = A[j];
acc1 += acc_eT(tmp_i * tmp_i);
acc2 += acc_eT(tmp_j * tmp_j);
acc1 += (tmp_i * tmp_i);
acc2 += (tmp_j * tmp_j);
}
if(i < N)
{
const eT tmp_i = A[i];
acc1 += acc_eT(tmp_i * tmp_i);
acc1 += (tmp_i * tmp_i);
}
acc = acc1 + acc2;
acc = (acc1 + acc2);
}
else
{
@@ -397,11 +391,14 @@ op_norm::vec_norm_2(const Proxy<T1>& P, const typename arma_not_cx<typename T1::
{
const eT tmp = P.at(0,col);
acc += acc_eT(tmp * tmp);
acc += (tmp * tmp);
}
}
else
{
eT acc1 = eT(0);
eT acc2 = eT(0);
for(uword col=0; col<n_cols; ++col)
{
uword i,j;
@@ -410,26 +407,27 @@ op_norm::vec_norm_2(const Proxy<T1>& P, const typename arma_not_cx<typename T1::
const eT tmp_i = P.at(i,col);
const eT tmp_j = P.at(j,col);
acc += acc_eT(tmp_i * tmp_i);
acc += acc_eT(tmp_j * tmp_j);
acc1 += (tmp_i * tmp_i);
acc2 += (tmp_j * tmp_j);
}
if(i < n_rows)
{
const eT tmp_i = P.at(i,col);
acc += acc_eT(tmp_i * tmp_i);
acc1 += (tmp_i * tmp_i);
}
}
acc = (acc1 + acc2);
}
}
const eT sqrt_acc = std::sqrt(acc);
const acc_eT sqrt_acc = std::sqrt(acc);
if( (sqrt_acc != acc_eT(0)) && arma_isfinite(sqrt_acc) )
if( (sqrt_acc != eT(0)) && arma_isfinite(sqrt_acc) )
{
return eT(sqrt_acc);
return sqrt_acc;
}
else
{
@@ -454,11 +452,7 @@ op_norm::vec_norm_2(const Proxy<T1>& P, const typename arma_cx_only<typename T1:
typedef typename T1::elem_type eT;
typedef typename T1::pod_type T;
typedef typename conditional_promote_type<is_real_or_cx<eT>::value, eT, float>::result acc_eT;
typedef typename get_pod_type<acc_eT>::result acc_T;
acc_T acc = acc_T(0);
T acc = T(0);
if(Proxy<T1>::use_at == false)
{
@@ -473,7 +467,7 @@ op_norm::vec_norm_2(const Proxy<T1>& P, const typename arma_cx_only<typename T1:
const T a = X.real();
const T b = X.imag();
acc += acc_T(a*a) + acc_T(b*b);
acc += (a*a) + (b*b);
}
}
else
@@ -490,7 +484,7 @@ op_norm::vec_norm_2(const Proxy<T1>& P, const typename arma_cx_only<typename T1:
const T a = X.real();
const T b = X.imag();
acc += acc_T(a*a) + acc_T(b*b);
acc += (a*a) + (b*b);
}
}
else
@@ -503,21 +497,25 @@ op_norm::vec_norm_2(const Proxy<T1>& P, const typename arma_cx_only<typename T1:
const T a = X.real();
const T b = X.imag();
acc += acc_T(a*a) + acc_T(b*b);
acc += (a*a) + (b*b);
}
}
}
const acc_T sqrt_acc = std::sqrt(acc);
const T sqrt_acc = std::sqrt(acc);
if( (sqrt_acc != acc_T(0)) && arma_isfinite(sqrt_acc) )
if( (sqrt_acc != T(0)) && arma_isfinite(sqrt_acc) )
{
return T(sqrt_acc);
return sqrt_acc;
}
else
{
arma_debug_print("detected possible underflow or overflow");
typedef typename promote_type<eT, float>::result acc_eT;
typedef typename get_pod_type<acc_eT>::result acc_T;
const quasi_unwrap<typename Proxy<T1>::stored_type> R(P.Q);
const uword N = R.M.n_elem;
@@ -606,13 +604,13 @@ op_norm::vec_norm_2_direct_std(const Mat<eT>& X, const typename arma_fp16_real_o
{
arma_debug_sigprint();
arma_ignore(junk);
const uword N = X.n_elem;
const eT* A = X.memptr();
// fp16 support must be non-BLAS
eT out_val = op_norm::vec_norm_2_direct_mem(N,A);
if( (out_val != eT(0)) && arma_isfinite(out_val) )
{
return (out_val < eT(0)) ? eT(0) : out_val;
@@ -620,7 +618,7 @@ op_norm::vec_norm_2_direct_std(const Mat<eT>& X, const typename arma_fp16_real_o
else
{
arma_debug_print("detected possible underflow or overflow");
return op_norm::vec_norm_2_direct_robust(X);
}
}
@@ -634,31 +632,29 @@ op_norm::vec_norm_2_direct_mem(const uword N, const eT* A)
{
arma_debug_sigprint();
typedef typename conditional_promote_type<is_real_or_cx<eT>::value, eT, float>::result acc_eT;
acc_eT acc = acc_eT(0);
eT acc = eT(0);
#if (defined(ARMA_SIMPLE_LOOPS) || defined(__FAST_MATH__))
{
acc_eT acc1 = acc_eT(0);
eT acc1 = eT(0);
if(memory::is_aligned(A))
{
memory::mark_as_aligned(A);
for(uword i=0; i<N; ++i) { const eT tmp_i = A[i]; acc1 += acc_eT(tmp_i * tmp_i); }
for(uword i=0; i<N; ++i) { const eT tmp_i = A[i]; acc1 += (tmp_i * tmp_i); }
}
else
{
for(uword i=0; i<N; ++i) { const eT tmp_i = A[i]; acc1 += acc_eT(tmp_i * tmp_i); }
for(uword i=0; i<N; ++i) { const eT tmp_i = A[i]; acc1 += (tmp_i * tmp_i); }
}
acc = acc1;
}
#else
{
acc_eT acc1 = acc_eT(0);
acc_eT acc2 = acc_eT(0);
eT acc1 = eT(0);
eT acc2 = eT(0);
uword j;
@@ -667,22 +663,22 @@ op_norm::vec_norm_2_direct_mem(const uword N, const eT* A)
const eT tmp_i = (*A); A++;
const eT tmp_j = (*A); A++;
acc1 += acc_eT(tmp_i * tmp_i);
acc2 += acc_eT(tmp_j * tmp_j);
acc1 += (tmp_i * tmp_i);
acc2 += (tmp_j * tmp_j);
}
if((j-1) < N)
{
const eT tmp_i = (*A);
acc1 += acc_eT(tmp_i * tmp_i);
acc1 += (tmp_i * tmp_i);
}
acc = acc1 + acc2;
}
#endif
return eT(std::sqrt(acc));
return std::sqrt(acc);
}
@@ -694,10 +690,43 @@ op_norm::vec_norm_2_direct_robust(const Mat<eT>& X)
{
arma_debug_sigprint();
typedef typename conditional_promote_type<is_real_or_cx<eT>::value, eT, float>::result acc_eT;
typedef typename promote_type<eT, float>::result acc_eT;
const uword N = X.n_elem;
const eT* A = X.memptr();
if(is_fp16<eT>::yes)
{
// try straightforward type promotion before the default slow algorithm
const eT* X_mem = X.memptr();
acc_eT acc1 = acc_eT(0);
acc_eT acc2 = acc_eT(0);
uword j;
for(j=1; j<N; j+=2)
{
const acc_eT tmp_i = acc_eT(*X_mem); X_mem++;
const acc_eT tmp_j = acc_eT(*X_mem); X_mem++;
acc1 += (tmp_i * tmp_i);
acc2 += (tmp_j * tmp_j);
}
if((j-1) < N)
{
const acc_eT tmp_i = acc_eT(*X_mem);
acc1 += (tmp_i * tmp_i);
}
const acc_eT sqrt_acc = std::sqrt(acc1 + acc2);
if( (sqrt_acc != acc_eT(0)) && arma_isfinite(sqrt_acc) ) { return eT(sqrt_acc); }
}
const eT* A = X.memptr();
acc_eT max_val = priv::most_neg<acc_eT>();
@@ -737,15 +766,15 @@ op_norm::vec_norm_2_direct_robust(const Mat<eT>& X)
val_i /= max_val;
val_j /= max_val;
acc1 += val_i * val_i;
acc2 += val_j * val_j;
acc1 += (val_i * val_i);
acc2 += (val_j * val_j);
}
if((j-1) < N)
{
const acc_eT val_i = acc_eT(*B) / max_val;
acc1 += val_i * val_i;
acc1 += (val_i * val_i);
}
const acc_eT out_val = std::sqrt(acc1 + acc2) * max_val;