After discovering that App Inventor represents numbers in floating-point, I wanted to see how it handled some edge case decimal/floating-point conversions. In one group of tests, I gave it numbers that were converted to floating-point incorrectly in other programming languages (I include the famous PHP and Java numbers). In another group of tests, I gave it numbers that, when converted to floating-point and back, demonstrate the rounding algorithm used when printing halfway cases. It turns out that App Inventor converts all examples correctly, and prints numbers using the round-half-to-even rule.
A Decimal To Floating-Point Conversion That Hung PHP
PHP went into an infinite loop when trying to convert the number 2.2250738585072011e-308 to floating-point; App Inventor converts it correctly:
As you can see in the blocks, App Inventor converts the input upon entry and displays it as 2.225073858507201e-308. That’s OK though. It still converts to the same number, which is the largest subnormal double-precision floating-point number: 0x0.fffffffffffffp-1022. (In binary, it has 1022 leading 0s followed by 52 1s.)
A Decimal To Floating-Point Conversion That Hung Java
Java went into an infinite loop when trying to convert the number 2.2250738585072012e-308; App Inventor converts it correctly:
App Inventor converts the input upon entry and displays it as 2.2250738585072014e-308. This converts to the same floating-point number as 2.2250738585072012e-308: 0x1p-1022, or DBL_MIN. (In binary, it has 1021 leading 0s followed by one 1).
A Decimal To Floating-Point Conversion Java Did Incorrectly
This is the number 2-1047 + 2-1075.
App Inventor converts it correctly:
App Inventor converts the input upon entry and displays it as 6.63123685e-316, which converts to the same floating-point number: 2-1047. (In binary, it has 1046 0s followed by one 1.)
(If you were to round the input number to 9 digits you would get 6.63123687e-316, not 6.63123685e-316. But this is OK, since the full-precision floating-point number that 6.63123687e-316 converts to rounds to 6.63123685e-316. Note that, since this is a subnormal number, which happens to have only 28 bits of precision, 9 decimal digits is sufficient to specify it.)
A Decimal To Floating-Point Conversion strtod() Did Incorrectly
David Gay’s strtod(), which is used in many programming language implementations, converted this number incorrectly:
This number is very close to 2-1075; it is just a tiny bit bigger.
App Inventor converts it correctly:
App Inventor converts the input upon entry and displays it as 5e-324, which converts to the same floating-point number: 2-1074. (In binary, it has 1073 0s followed by one 1.)
Rounding In Floating-Point To Decimal Conversions
Different languages round printed floating-point numbers differently. Some round halfway cases according to the round-half-away-from-zero rule, and some round according to the round-half-to-even rule. App Inventor uses the round-half-to-even rule.
I tested a few examples from the referenced article. In each case, the number has two decimal places, but I print it rounded to one place. All look like halfway cases in decimal, but in floating-point, only two really are. Here are the results (I will not show the screen captures of the blocks or emulator output):
- 0.25 rounds to 0.2. 0.25 is exactly representable in floating-point, so this is a halfway case. App Inventor rounds down to even.
- 0.75 rounds to 0.8. 0.75 is exactly representable in floating-point, so this is a halfway case. App Inventor rounds up to even.
- 0.15 rounds to 0.1. 0.15 is inexact in floating-point, taking on a value slightly less than 0.15; so this is not a halfway case. App Inventor correctly rounds down.
- 0.85 rounds to 0.8. 0.85 is inexact in floating-point, taking on a value slightly less than 0.85; so this is not a halfway case. App Inventor correctly rounds down.
- 0.55 rounds to 0.6. 0.55 is inexact in floating-point, taking on a value slightly greater than 0.55; so this is not a halfway case. App Inventor correctly rounds up.
- 0.45 rounds to 0.5. 0.45 is inexact in floating-point, taking on a value slightly greater than 0.45; so this is not a halfway case. App Inventor correctly rounds up.