MEL How-To #39 | ||
| ||
How do I deal with those weird float values that I get instead of zero (e.g. -8.881784329e-017)?These results represent the almost-but-not-quite-zero values that Maya often returns. Unless you're modelling atoms you can safely ignore values this small. To counter this behavior, I typically run calculations through a precision rounder, such as the following: proc float precision( float $value, int $dec ) // $value == value to round off // $dec == number of decimal places { float $bump = 0.5; if ($value < 0.0) $bump = -0.5; $value = trunc( $value * pow( 10, $dec ) + $bump ) / pow( 10, $dec ); return $value; } Duncan Brinsmead (Chief Scientist, Alias) noted that my function does not work properly when supplied with a negative number of decimal places (for rounding to 10s, 100s, etc). Mr. Brinsmead generously provided his own function which handles this properly: // Procedure Name: roundoff // // Author: Duncan Brinsmead // // Description: // simple function to round float values to a particular decimal // // Usage: roundoff <float value> <number of decimal places> // // examples // // roundoff -1.119 2 // Result: -1.12 // // roundoff 256.812 0 // Result: 257 // // roundoff 128.1 -1 // Result: 130 global proc float roundoff( float $f, int $n ) { // we divide if n < 0 to avoid numeric // precision problems if( $n > 0 ) { float $roundScale = pow(10,$n); if( $f > 0 ) return( ((float)(int)($f * $roundScale + 0.5)) /$roundScale ); else return( ((float)(int)($f * $roundScale - 0.5)) /$roundScale ); } else { float $roundScale = pow(10,-$n); if( $f > 0 ) return( ((float)(int)($f/$roundScale + 0.5)) *$roundScale ); else return( ((float)(int)($f/$roundScale - 0.5)) *$roundScale ); } } Reproduced with permission from the author. Converting from scientific to fixed point David Biggs contributed the following "formatFloat" MEL procedure which can return a fixed point representation from the scientific format used for these infinitesimal floating point values. proc string formatFloat(float $f,int $precision) { int $wasNegative = 0; if($f < 0) { $f *= -1; $wasNegative = 1; } string $result = ""; int $b = 0; int $n = 12; while($n > -$precision) { float $temp = pow(10,$n); int $g = (int)($f/$temp); if($n == -1) { if($b == 0) { $b = 1; $result += "0"; } $result += "."; } if($g > 0) { $b = 1; $f = $f -($g * $temp); $result += $g; } else if($b == 1) { $result += "0"; } $n--; } if($wasNegative) $result = "-" + $result; return $result; } Example: formatFloat(-8.881784329e-017,25); // Result: -0.000000000000000088817843 // It can be susceptible to floating point precision loss (like all things that use floating point), so be wary of its results with values more significant than these infinitesimal values. formatFloat( -0.08881784329, 25 ); // Result: -0.088817843290000001793391 // formatFloat( 888.1784329, 25 ); // Result: 888.178432899999961579272769 // Acknowledgements
23 Sep 2004 | ||
Copyright ©2005 by Bryan Ewert, maya@ewertb.com Maya is a Registered Trademark of Alias |