time-to-botec

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

main.js (3759B)


      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 isPositiveInteger = require( '@stdlib/assert/is-positive-integer' ).isPrimitive;
     24 var isnan = require( '@stdlib/math/base/assert/is-nan' );
     25 var PINF = require( '@stdlib/constants/float64/pinf' );
     26 var NINF = require( '@stdlib/constants/float64/ninf' );
     27 var Float64Array = require( '@stdlib/array/float64' );
     28 
     29 
     30 // MAIN //
     31 
     32 /**
     33 * Returns an accumulator function which incrementally computes a moving mid-range.
     34 *
     35 * @param {PositiveInteger} W - window size
     36 * @throws {TypeError} must provide a positive integer
     37 * @returns {Function} accumulator function
     38 *
     39 * @example
     40 * var accumulator = incrmmidrange( 3 );
     41 *
     42 * var mr = accumulator();
     43 * // returns null
     44 *
     45 * mr = accumulator( 2.0 );
     46 * // returns 2.0
     47 *
     48 * mr = accumulator( -5.0 );
     49 * // returns -1.5
     50 *
     51 * mr = accumulator( 3.0 );
     52 * // returns -1.0
     53 *
     54 * mr = accumulator( 5.0 );
     55 * // returns 0.0
     56 *
     57 * mr = accumulator();
     58 * // returns 0.0
     59 */
     60 function incrmmidrange( W ) {
     61 	var buf;
     62 	var min;
     63 	var max;
     64 	var N;
     65 	var i;
     66 	if ( !isPositiveInteger( W ) ) {
     67 		throw new TypeError( 'invalid argument. Must provide a positive integer. Value: `' + W + '`.' );
     68 	}
     69 	buf = new Float64Array( W );
     70 	min = PINF;
     71 	max = NINF;
     72 	i = -1;
     73 	N = 0;
     74 
     75 	return accumulator;
     76 
     77 	/**
     78 	* If provided a value, the accumulator function returns an updated mid-range. If not provided a value, the accumulator function returns the current mid-range.
     79 	*
     80 	* @private
     81 	* @param {number} [x] - input value
     82 	* @returns {(number|null)} mid-range or null
     83 	*/
     84 	function accumulator( x ) {
     85 		var v;
     86 		var k;
     87 		if ( arguments.length === 0 ) {
     88 			if ( N === 0 ) {
     89 				return null;
     90 			}
     91 			return ( max+min ) / 2.0;
     92 		}
     93 		// Update the index for managing the circular buffer:
     94 		i = (i+1) % W;
     95 
     96 		if ( x === 0.0 ) {
     97 			x = 0.0; // normalizes +-0
     98 		}
     99 		// Case: incoming value is NaN...
    100 		if ( isnan( x ) ) {
    101 			N = W; // explicitly set to avoid `N < W` branch
    102 			min = x;
    103 			max = x;
    104 		}
    105 		// Case: initial window...
    106 		else if ( N < W ) {
    107 			N += 1;
    108 			if ( x < min ) {
    109 				min = x;
    110 			}
    111 			if ( x > max ) {
    112 				max = x;
    113 			}
    114 		}
    115 		// 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...
    116 		else if (
    117 			( buf[ i ] === min && x > min ) ||
    118 			( buf[ i ] === max && x < max ) ||
    119 			isnan( buf[ i ] )
    120 		) {
    121 			min = x;
    122 			max = x;
    123 			for ( k = 0; k < W; k++ ) {
    124 				if ( k !== i ) {
    125 					v = buf[ k ];
    126 					if ( isnan( v ) ) {
    127 						min = v;
    128 						max = v;
    129 						break; // no need to continue searching
    130 					}
    131 					if ( v < min ) {
    132 						min = v;
    133 					}
    134 					if ( v > max ) {
    135 						max = v;
    136 					}
    137 				}
    138 			}
    139 		}
    140 		// Case: incoming value is less than current minimum value...
    141 		else if ( x < min ) {
    142 			min = x;
    143 		}
    144 		// Case: incoming value is greater than current maximum value...
    145 		else if ( x > max ) {
    146 			max = x;
    147 		}
    148 		// Case: updating existing window; however, the minimum and maximum values do not change so nothing to do but update our buffer...
    149 		buf[ i ] = x;
    150 
    151 		return ( max+min ) / 2.0;
    152 	}
    153 }
    154 
    155 
    156 // EXPORTS //
    157 
    158 module.exports = incrmmidrange;