Hi,
the standard floor / ceil functions work inside a unit interval, by taking the input value to left or to the right end respectively.
I wrote this function which basically splits the interval into an arbitrary number of uniform portions and then applies floor / ceil by assuming that the new ends are those of the portion where the input value belongs to.
For instance, let a = 0.33
standard floor( 0.33) = 0, ceil (0.33) = 1
assuming 4 portions
floor(0.33) = 0.24, ceil (0.33) = 0.5
Here’s the code:
function closest_approx( _value, _n_portions = 1, _ceil = 0 )
{
if ( _n_portions <= 0 ) return undefined;
else
{
var _work_value = _value - ( _value | 0 ); //take to the unit interval
//% is mod function, replace with your preferred language version
var _p = 1.0 / _n_portions, _mod = _work_value % _p;
if ( _ceil === -1 && _mod >= _p / 2.0 )
{
if ( _mod >= _p / 2.0 )
return Math.ceil( _value * _n_portions ) / _n_portions;
return Math.floor( _value * _n_portions ) / _n_portions;
}
else if ( _ceil === 1 )
return Math.ceil( _value * _n_portions ) / _n_portions;
else if ( _ceil === 0 )
return Math.floor( _value * _n_portions ) / _n_portions;
}
}
var _n_portions = 1;
console.log( "First example - a sequence of values in the unit interval - 1 portion", "\n" );
console.log( "1 portion yields the standard floor / ceil services", "\n" );
console.log( "|------------------------------|--------------------------------|", "\n" );
console.log( "0---------------------------------------------------------------1", "\n" );
for( var _i = 0; _i <= 1; _i += 0.1 )
{
console.log( "input value: " + _i.toPrecision(_n_portions),
" | normal:" + closest_approx( _i, _n_portions ).toPrecision(_n_portions),
" | force ceil: " + closest_approx( _i, _n_portions, 1 ).toPrecision(_n_portions),
" | force floor: " + closest_approx( _i, _n_portions, 0 ).toPrecision(_n_portions)
);
}
_n_portions = 2;
console.log( "\n\nSecond example - a sequence of values in the unit interval - 2 portions", "\n" );
console.log( "|------------------------------|--------------------------------|", "\n" );
console.log( "0-----------------------------0.5-------------------------------1", "\n" );
for( var _i = 0; _i <= 1; _i += 0.1 )
{
console.log( "input value: " + _i.toPrecision(_n_portions),
" | normal:" + closest_approx( _i, _n_portions ).toPrecision(_n_portions),
" | force ceil: " + closest_approx( _i, _n_portions, 1 ).toPrecision(_n_portions),
" | force floor: " + closest_approx( _i, _n_portions, 0 ).toPrecision(_n_portions)
);
}
_n_portions = 4;
console.log( "\n\Third example - a sequence outside the unit interval - 4 portions", "\n" );
console.log( "|-------------|-------------|-------------|-------------|", "\n" );
console.log( "17-----------17.25--------17.50----------17.75----------18", "\n" );
for( var _i = 17; _i <= 18; _i += 0.1 )
{
console.log( "input value: " + _i.toPrecision(_n_portions),
" | normal:" + closest_approx( _i, _n_portions ).toPrecision(_n_portions),
" | force ceil: " + closest_approx( _i, _n_portions, 1 ).toPrecision(_n_portions),
" | force floor: " + closest_approx( _i, _n_portions, 0 ).toPrecision(_n_portions)
);
}