Testing Some Edge Case Conversions In App Inventor

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:

http://www.exploringbinary.com/wp-content/uploads/AI.PHP-Hangs.blocks.png
App Inventor Blocks To Display All Digits Of 2.2250738585072011e-308
http://www.exploringbinary.com/wp-content/uploads/AI.PHP-Hangs.emulator.png
Emulator Output Showing All Digits Of 2.2250738585072011e-308

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:

http://www.exploringbinary.com/wp-content/uploads/AI.Java-Hangs.blocks.png
App Inventor Blocks To Display All Digits Of 2.2250738585072012e-308
http://www.exploringbinary.com/wp-content/uploads/AI.Java-Hangs.emulator.png
Emulator Output Showing All Digits Of 2.2250738585072012e-308

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

Here’s a subnormal number Java converted incorrectly:

6.631236871469758276785396630275967243399099947355303144249971758736286630139265439618068200788048744105960420552601852889715006376325666595539603330361800519107591783233358492337208057849499360899425128640718856616503093444922854759159988160304439909868291973931426625698663157749836252274523485312442358651207051292453083278116143932569727918709786004497872322193856150225415211997283078496319412124640111777216148110752815101775295719811974338451936095907419622417538473679495148632480391435931767981122396703443803335529756003353209830071832230689201383015598792184172909927924176339315507402234836120730914783168400715462440053817592702766213559042115986763819482654128770595766806872783349146967171293949598850675682115696218943412532098591327667236328125E-316

This is the number 2-1047 + 2-1075.

App Inventor converts it correctly:

http://www.exploringbinary.com/wp-content/uploads/AI.Incorrect-java-subnormal-ex1.blocks.png
App Inventor Blocks To Display All Digits Of A Number Java Converted Incorrectly
http://www.exploringbinary.com/wp-content/uploads/AI.Incorrect-java-subnormal-ex1.emulator.png
Emulator Output Showing All Digits Of The Number Java Converted Incorrectly

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:

2.4703282292062327208828439643411068618252990130716238221279284125033775363510437593264991818081799618989828234772285886546332835517796989819938739800539093906315035659515570226392290858392449105184435931802849936536152500319370457678249219365623669863658480757001585769269903706311928279558551332927834338409351978015531246597263579574622766465272827220056374006485499977096599470454020828166226237857393450736339007967761930577506740176324673600968951340535537458516661134223766678604162159680461914467291840300530057530849048765391711386591646239524912623653881879636239373280423891018672348497668235089863388587925628302755995657524455507255189313690836254779186948667994968324049705821028513185451396213837722826145437693412532098591327667236328125001e-324

This number is very close to 2-1075; it is just a tiny bit bigger.

App Inventor converts it correctly:

http://www.exploringbinary.com/wp-content/uploads/AI.Gays-strtod-returns-0-just-above-2--1075.blocks.png
App Inventor Blocks To Display All Digits Of A Number strtod() Converted Incorrectly
http://www.exploringbinary.com/wp-content/uploads/AI.Gays-strtod-returns-0-just-above-2--1075.emulator.png
Emulator Output Showing All Digits Of The Number strtod() Converted Incorrectly

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.
Dingbat
RSS feed icon
RSS e-mail icon

Leave a Reply

Your email address will not be published. Required fields are marked *

(Cookies must be enabled to leave a comment...it reduces spam.)