Fumio Nonaka wrote:
2 floating point numbers are NOT "close enough". That IS the problem.
var _str:String = "1.2e+51";
var n:Number = parseFloat(_str);
trace((n-1.2e+51) > 100000000000000000000000000000000000); // true
In ActionScript 3, the native Number data type is internally represented
as a IEEE-754 double-precision floating-point number. Due to the way
that the IEEE-754 standard defines how the bits are used to represent
the number, the accuracy of the mantissa precision (always 52 bits, or
16 decimal digits) changes depending on the exponent (always 11 bits).
See: http://en.wikipedia.org/wiki/IEEE_754
This is to say, the "close enough" value that you need to compare the
absolute difference between the two Numbers scales in magnitude with the
exponent. This can be particularly bad if you need arbitrary precision,
(e.g. when doing financial or scientific calcuations), as while 1.32e+36
is paltry compared to 1.2e+51, no one would want to be swindled out of
1.32e+36 dollars due to faulty floating point comparisons, hence the
need for arbitrary precision integer libraries for such applications as
was recently mentioned on this list.
Fortunately however, if you don't need this kind of exact precision, but
simply need to match large values originally parsed from strings to
Numbers as per your example, there is a much better and easier way to
compare very large Numbers in ActionScript 3--by inspecting them at the
bit level following the IEEE-754 specification.
From previous data packing experiments, I've found that the last nibble
(4 bits) of a 64-bit Number isn't reliable when you're casting to and
from Numbers (e.g. reading 8 bytes out of a ByteArray into a Number or
doing round-trips via the toString and parseFloat methods). I'm not
sure why this is the case--perhaps someone from Adobe can reply and
speak to this particular issue.
That being said, all you really need to do for a nearly-equals Number
comparison is a byte-by-byte comparison save for the last byte, in which
case you only compare the four most significant bits. If all bits aside
from the last nibble match, the Numbers are close enough.
Here's how I do it:
<code>
/**
* Compare two ActionScript 3 Numbers for near-equality.
*
* @param The first Number
* @param The second Number
*
* @return True on near-equality, false otherwise.
*/
public function closeEnough(a:Number, b:Number):Boolean {
var ba:ByteArray, i:uint;
if (a == b) {
// A is explicitly equal to B
return true;
}
else {
// A isn't exactly equal to B, so we need to
// check the Numbers' bytes one byte at a time.
ba = new ByteArray();
ba.writeDouble(a);
ba.writeDouble(b);
// If any of the first 7 bytes differ, then
// the two values are not close enough.
for (i = 0; i < 7; i++) {
if (ba[i] != ba[i + 8]) {
return false;
}
}
// Mask the last four bits out and compare the
// last byte. If they match, the Numbers are
// close enough. The last nibble tends not to
// be reliable enough for comparison, so we
// allow these to differ and the two Numbers
// still be considered close enough.
if ((ba[7] & 0xf0) != (ba[15] & 0xf0)) {
return false;
}
}
return true;
}
</code>
Jim Cheng
effectiveUI
_______________________________________________
Flashcoders@chattyfig.figleaf.com
To change your subscription options or search the archive:
http://chattyfig.figleaf.com/mailman/listinfo/flashcoders
Brought to you by Fig Leaf Software
Premier Authorized Adobe Consulting and Training
http://www.figleaf.com
http://training.figleaf.com