@@ -2032,14 +2032,14 @@ math_fmod_impl(PyObject *module, double x, double y)
2032
2032
}
2033
2033
2034
2034
/*
2035
- Given an *n* length *vec* of non-negative values
2036
- where *max* is the largest value in the vector, compute:
2035
+ Given an *n* length *vec* of values and a value *max*, compute:
2037
2036
2038
2037
max * sqrt(sum((x / max) ** 2 for x in vec))
2039
2038
2040
- The value of the *max* variable must be present in *vec*
2041
- or should equal to 0.0 when n==0. Likewise, *max* will
2042
- be INF if an infinity is present in the vec.
2039
+ The value of the *max* variable must be non-negative and
2040
+ at least equal to the absolute value of the largest magnitude
2041
+ entry in the vector. If n==0, then *max* should be 0.0.
2042
+ If an infinity is present in the vec, *max* should be INF.
2043
2043
2044
2044
The *found_nan* variable indicates whether some member of
2045
2045
the *vec* is a NaN.
@@ -2053,16 +2053,19 @@ The *csum* variable tracks the cumulative sum and *frac* tracks
2053
2053
the cumulative fractional errors at each step. Since this
2054
2054
variant assumes that |csum| >= |x| at each step, we establish
2055
2055
the precondition by starting the accumulation from 1.0 which
2056
- represents an entry equal to *max*. This also provides a nice
2057
- side benefit in that it lets us skip over a *max* entry (which
2058
- is swapped into *last*) saving us one iteration through the loop.
2056
+ represents the largest possible value of (x/max)**2.
2057
+
2058
+ After the loop is finished, the initial 1.0 is subtracted out
2059
+ for a net zero effect on the final sum. Since *csum* will be
2060
+ greater than 1.0, the subtraction of 1.0 will not cause
2061
+ fractional digits to be dropped from *csum*.
2059
2062
2060
2063
*/
2061
2064
2062
2065
static inline double
2063
2066
vector_norm (Py_ssize_t n , double * vec , double max , int found_nan )
2064
2067
{
2065
- double x , csum = 1.0 , oldcsum , frac = 0.0 , last ;
2068
+ double x , csum = 1.0 , oldcsum , frac = 0.0 ;
2066
2069
Py_ssize_t i ;
2067
2070
2068
2071
if (Py_IS_INFINITY (max )) {
@@ -2071,27 +2074,20 @@ vector_norm(Py_ssize_t n, double *vec, double max, int found_nan)
2071
2074
if (found_nan ) {
2072
2075
return Py_NAN ;
2073
2076
}
2074
- if (max == 0.0 ) {
2075
- return 0.0 ;
2077
+ if (max == 0.0 || n == 1 ) {
2078
+ return max ;
2076
2079
}
2077
- assert (n > 0 );
2078
- last = vec [n - 1 ];
2079
- for (i = 0 ; i < n - 1 ; i ++ ) {
2080
+ for (i = 0 ; i < n ; i ++ ) {
2080
2081
x = vec [i ];
2081
- assert (Py_IS_FINITE (x ) && x >= 0.0 && x <= max );
2082
- if (x == max ) {
2083
- x = last ;
2084
- last = max ;
2085
- }
2082
+ assert (Py_IS_FINITE (x ) && fabs (x ) <= max );
2086
2083
x /= max ;
2087
2084
x = x * x ;
2088
- assert (csum >= x );
2089
2085
oldcsum = csum ;
2090
2086
csum += x ;
2087
+ assert (csum >= x );
2091
2088
frac += (oldcsum - csum ) + x ;
2092
2089
}
2093
- assert (last == max );
2094
- return max * sqrt (csum + frac );
2090
+ return max * sqrt (csum - 1.0 + frac );
2095
2091
}
2096
2092
2097
2093
#define NUM_STACK_ELEMS 16
0 commit comments