// We can probably do better than this. See for example:
// http://dss.stephanierct.com/DevBlog/?p=8
NV_FORCEINLINEintftoi_floor(floatval){
returnftoi_round(floorf(val));
}
NV_FORCEINLINEintftoi_ceil(floatval){
returnftoi_round(ceilf(val));
}
#else
// In theory this should work with any double floating point math implementation, but it appears that MSVC produces incorrect code
// when SSE2 is targeted and fast math is enabled (/arch:SSE2 & /fp:fast). These problems go away with /fp:precise, which is the default mode.
NV_FORCEINLINEintftoi_round(floatval){
returnftoi_round_xs(val);
}
NV_FORCEINLINEintftoi_floor(floatval){
returnftoi_floor_xs(val);
}
NV_FORCEINLINEintftoi_ceil(floatval){
returnftoi_ceil_xs(val);
}
NV_FORCEINLINEintftoi_trunc(floatf){
returnftoi_trunc_xs(f);
}
#endif
inlinevoidtest_ftoi(){
// Round to nearest integer.
nvCheck(ftoi_round(0.1f)==0);
nvCheck(ftoi_round(0.6f)==1);
nvCheck(ftoi_round(-0.2f)==0);
nvCheck(ftoi_round(-0.7f)==-1);
nvCheck(ftoi_round(10.1f)==10);
nvCheck(ftoi_round(10.6f)==11);
nvCheck(ftoi_round(-90.1f)==-90);
nvCheck(ftoi_round(-90.6f)==-91);
nvCheck(ftoi_round(0)==0);
nvCheck(ftoi_round(1)==1);
nvCheck(ftoi_round(-1)==-1);
nvCheck(ftoi_round(0.5f)==0);// How are midpoints rounded? Bankers rounding.
nvCheck(ftoi_round(1.5f)==2);
nvCheck(ftoi_round(2.5f)==2);
nvCheck(ftoi_round(3.5f)==4);
nvCheck(ftoi_round(4.5f)==4);
nvCheck(ftoi_round(-0.5f)==0);
nvCheck(ftoi_round(-1.5f)==-2);
// Truncation (round down if > 0, round up if < 0).
nvCheck(ftoi_trunc(0.1f)==0);
nvCheck(ftoi_trunc(0.6f)==0);
nvCheck(ftoi_trunc(-0.2f)==0);
nvCheck(ftoi_trunc(-0.7f)==0);// @@ When using /arch:SSE2 in Win32, msvc produce wrong code for this one. It is skipping the addition.
nvCheck(ftoi_trunc(1.99f)==1);
nvCheck(ftoi_trunc(-1.2f)==-1);
// Floor (round down).
nvCheck(ftoi_floor(0.1f)==0);
nvCheck(ftoi_floor(0.6f)==0);
nvCheck(ftoi_floor(-0.2f)==-1);
nvCheck(ftoi_floor(-0.7f)==-1);
nvCheck(ftoi_floor(1.99f)==1);
nvCheck(ftoi_floor(-1.2f)==-2);
nvCheck(ftoi_floor(0)==0);
nvCheck(ftoi_floor(1)==1);
nvCheck(ftoi_floor(-1)==-1);
nvCheck(ftoi_floor(2)==2);
nvCheck(ftoi_floor(-2)==-2);
// Ceil (round up).
nvCheck(ftoi_ceil(0.1f)==1);
nvCheck(ftoi_ceil(0.6f)==1);
nvCheck(ftoi_ceil(-0.2f)==0);
nvCheck(ftoi_ceil(-0.7f)==0);
nvCheck(ftoi_ceil(1.99f)==2);
nvCheck(ftoi_ceil(-1.2f)==-1);
nvCheck(ftoi_ceil(0)==0);
nvCheck(ftoi_ceil(1)==1);
nvCheck(ftoi_ceil(-1)==-1);
nvCheck(ftoi_ceil(2)==2);
nvCheck(ftoi_ceil(-2)==-2);
}
// Safe versions using standard casts.
inlineintiround(floatf)
{
returnftoi_round(f);
//return int(floorf(f + 0.5f));
}
inlineintiround(doublef)
{
returnint(::floor(f+0.5));
}
inlineintifloor(floatf)
{
returnftoi_floor(f);
//return int(floorf(f));
}
inlineinticeil(floatf)
{
returnint(ceilf(f));
}
// I'm always confused about which quantizer to use. I think we should choose a quantizer based on how the values are expanded later and this is generally using the 'exact endpoints' rule.
// Some notes from cbloom: http://cbloomrants.blogspot.com/2011/07/07-26-11-pixel-int-to-float-options.html
// Quantize a float in the [0,1] range, using exact end points or uniform bins.