time-to-botec

Benchmark sampling in different programming languages
Log | Files | Refs | README

minmax.js (5050B)


      1 /**
      2 * @license Apache-2.0
      3 *
      4 * Copyright (c) 2018 The Stdlib Authors.
      5 *
      6 * Licensed under the Apache License, Version 2.0 (the "License");
      7 * you may not use this file except in compliance with the License.
      8 * You may obtain a copy of the License at
      9 *
     10 *    http://www.apache.org/licenses/LICENSE-2.0
     11 *
     12 * Unless required by applicable law or agreed to in writing, software
     13 * distributed under the License is distributed on an "AS IS" BASIS,
     14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15 * See the License for the specific language governing permissions and
     16 * limitations under the License.
     17 */
     18 
     19 'use strict';
     20 
     21 // MODULES //
     22 
     23 var isPositiveZero = require( '@stdlib/math/base/assert/is-positive-zero' );
     24 var isNegativeZero = require( '@stdlib/math/base/assert/is-negative-zero' );
     25 var isnan = require( '@stdlib/math/base/assert/is-nan' );
     26 var PINF = require( '@stdlib/constants/float64/pinf' );
     27 var NINF = require( '@stdlib/constants/float64/ninf' );
     28 
     29 
     30 // MAIN //
     31 
     32 /**
     33 * Returns an accumulator function which incrementally computes moving minimum and maximum values.
     34 *
     35 * @private
     36 * @param {Collection} out - output array
     37 * @param {PositiveInteger} W - window size
     38 * @param {Collection} buf - data buffer
     39 * @returns {Function} accumulator function
     40 *
     41 * @example
     42 * var buf = [ 0.0, 0.0, 0.0 ];
     43 *
     44 * var accumulator = incrmminmax( [ 0.0, 0.0 ], 3, buf );
     45 *
     46 * var mm = accumulator( 2.0, 0 );
     47 * // returns [ 2.0, 2.0 ]
     48 *
     49 * buf[ 0 ] = 2.0;
     50 *
     51 * mm = accumulator( -5.0, 1 );
     52 * // returns [ -5.0, 2.0 ]
     53 *
     54 * buf[ 1 ] = -5.0;
     55 *
     56 * mm = accumulator( 3.0, 2 );
     57 * // returns [ -5.0, 3.0 ]
     58 *
     59 * buf[ 2 ] = 3.0;
     60 *
     61 * mm = accumulator( 5.0, 0 );
     62 * // returns [ -5.0, 5.0 ]
     63 *
     64 * buf[ 0 ] = 5.0;
     65 */
     66 function incrmminmax( out, W, buf ) {
     67 	var min;
     68 	var max;
     69 	var N;
     70 
     71 	min = PINF;
     72 	max = NINF;
     73 	N = 0;
     74 
     75 	return accumulator;
     76 
     77 	/**
     78 	* Updates accumulator state.
     79 	*
     80 	* @private
     81 	* @param {number} x - input value
     82 	* @param {NonNegativeInteger} i - buffer index
     83 	* @returns {Collection} output array
     84 	*/
     85 	function accumulator( x, i ) {
     86 		var sgn;
     87 		var v;
     88 		var k;
     89 
     90 		// Case: incoming value is NaN...
     91 		if ( isnan( x ) ) {
     92 			N = W; // explicitly set to avoid `N < W` branch
     93 			min = x;
     94 			max = x;
     95 		}
     96 		// Case: initial window...
     97 		else if ( N < W ) {
     98 			N += 1;
     99 			if ( x < min || ( x === min && isNegativeZero( x ) ) ) {
    100 				min = x;
    101 			}
    102 			if ( x > max || ( x === max && isPositiveZero( x ) ) ) {
    103 				max = x;
    104 			}
    105 		}
    106 		// Case: outgoing value is the current minimum or maximum and the new value is either greater than the minimum or less than the maximum, and, thus, we need to find new accumulated values among the current buffer values...
    107 		else if (
    108 			( buf[ i ] === min && x > min ) ||
    109 			( buf[ i ] === max && x < max ) ||
    110 			isnan( buf[ i ] )
    111 		) {
    112 			min = x;
    113 			max = x;
    114 			for ( k = 0; k < W; k++ ) {
    115 				if ( k !== i ) {
    116 					v = buf[ k ];
    117 					if ( isnan( v ) ) {
    118 						min = v;
    119 						max = v;
    120 						break; // no need to continue searching
    121 					}
    122 					if ( v < min || ( v === min && isNegativeZero( v ) ) ) {
    123 						min = v;
    124 					}
    125 					if ( v > max || ( v === max && isPositiveZero( v ) ) ) {
    126 						max = v;
    127 					}
    128 				}
    129 			}
    130 		}
    131 		// Case: incoming value is less than current minimum value...
    132 		else if ( x < min ) {
    133 			min = x;
    134 		}
    135 		// Case: incoming value is greater than current maximum value...
    136 		else if ( x > max ) {
    137 			max = x;
    138 		}
    139 		// Case: incoming value is zero, which means we need to be careful and correctly handle signed zeros...
    140 		else if ( x === 0.0 ) {
    141 			sgn = isNegativeZero( x );
    142 			if ( x === min ) {
    143 				// Case: outgoing value is the current minimum...
    144 				if (
    145 					buf[ i ] === min &&
    146 					isNegativeZero( buf[ i ] ) &&
    147 					sgn === false
    148 				) {
    149 					// Because the outgoing and incoming are different signs (-,+), we need to search the buffer to see if it contains a negative zero. If so, the minimum value remains negative zero; otherwise, the minimum value is incoming value...
    150 					min = x;
    151 					for ( k = 0; k < W; k++ ) {
    152 						if ( k !== i && isNegativeZero( buf[ k ] ) ) {
    153 							min = buf[ k ];
    154 							break;
    155 						}
    156 					}
    157 				} else if ( sgn ) {
    158 					// Ensure minimum value has the correct sign:
    159 					min = x;
    160 				}
    161 			}
    162 			if ( x === max ) {
    163 				// Case: outgoing value is the current maximum...
    164 				if (
    165 					buf[ i ] === max &&
    166 					isPositiveZero( buf[ i ] ) &&
    167 					sgn
    168 				) {
    169 					// Because the outgoing and incoming are different signs (+,-), we need to search the buffer to see if it contains a positive zero. If so, the maximum value remains positive zero; otherwise, the maximum value is incoming value...
    170 					max = x;
    171 					for ( k = 0; k < W; k++ ) {
    172 						if ( k !== i && isPositiveZero( buf[ k ] ) ) {
    173 							max = buf[ k ];
    174 							break;
    175 						}
    176 					}
    177 				} else if ( sgn === false ) {
    178 					// Ensure maximum value has the correct sign:
    179 					max = x;
    180 				}
    181 			}
    182 		}
    183 		// Case: updating existing window; however, the minimum and maximum values do not change so nothing to do...
    184 
    185 		out[ 0 ] = min;
    186 		out[ 1 ] = max;
    187 		return out;
    188 	}
    189 }
    190 
    191 
    192 // EXPORTS //
    193 
    194 module.exports = incrmminmax;