C. Keith Ray

C. Keith Ray writes about and develops software in multiple platforms and languages, including iOS® and Macintosh®.
Keith's Résumé (pdf)

Tuesday, January 21, 2014

FRACTIONS and computers

Fractions and computers: and when I say "computers," I am including the iPad, iPhone, iPod Touch as well as laptop and desktop computers.

If you work in traditional English units—inch, foot, pound, and so on—you are used to working with fractions. Instead of 3.25 inches, you would say 3¼ inches. Computers usually force you to work in decimals, like 3.25 inches, but there are a some issues with decimals, binary, and fractions you should know about.

You should know that computers can handle some fractions very well; these would be the powers-of-two fractions like ½, ¼, ⅛, and so on. This is because the computer represents numbers in a power-of-two fashion we call "binary". In binary there are only two digits: 0, and 1, and we arrange them in columns to make larger numbers. 

(binary) 101 = 1 × 2² + 0 × 2⁰ = 4 + 0 + 1 = 5.

In decimal, we have digits 0-9 and arrange them in columns to make larger numbers. The number 345 has a 3 in the 100's column, a 4 in the 10's column, and a 5 in the 1's column. Each column represents a power of 10.

(decimal) 345 = (3 × 100) + (4 × 10) + (5 × 1)
= (3 × 10²) + (4 × 10¹) + (5 × 10⁰)

On other side of the decimal point, the columns are also powers of ten, but the exponents are negative powers. The number 0.728 has a 7 in the tenth's column, a 2 in the hundreth's column, and an 8 in the thousanth's column.

(decimal) 0.728  = ⁷/₁₀ + ²/₁₀₀ + ⁸/₁₀₀₀
= (7 × 10⁻¹) + (2 × 10⁻²) + (8 × 10⁻³)
= (7 ÷ 10) + (2 ÷ 100) + (8 ÷ 1000)

Here's the scary part. Computers do not handle decimal fractions that are a power of ten very well, like ¹/₁₀ (which is 10⁻¹), ¹/₁₀₀ (which is 10⁻²), or ¹/₁₀₀₀.  (which is 10⁻³.) Because computers think in binary, the fraction one-tenth does not translate well into binary numbers. This is a problem similar to how some numbers are represented in decimal. For example, 1/7 is represented as a series of endlessly repeating digits in decimal: 0.14285714285714…

Similarly, decimal 1/10 in binary is an endlessly repeating sequence of binary digits to the right of the "binary point": 0.000110011….

decimal 1/10 = binary 0.000110011… =
= (0 × 2⁻¹) + (0 × 2⁻²) + (0 × 2⁻³) + (1 × 2⁻⁴) + (1 × 2⁻⁵) 
+ (0 × 2⁻⁶) + (0 × 2⁻⁷) + (1 × 2⁻⁸) + (1 × 2⁻⁹)…
= 0/2 + 0/4 + 0/8 + 1/16 + 1/32 + 0/64 + 0/128 
+ 1/256 + 1/512…
= 0 + 0 + 0 + 0.0625 + 0.03125 + 0 + 0 + 0.00390625 + 0.001953125…
= 0.099609375…

No matter how many binary digits we use to the right of the binary point, we can't get a value that exactly matches the decimal fraction 1/10, though it can get pretty close.


Why should this bother you?

It has to do with adding and multiplying. In many situations while using a computer, if you add the binary equivalent of one-tenth, ten times, you won't get the 1.0 you expect, unless those systems have taken precautions beyond the scope of this essay. 

In some systems, 0.1 translated to binary and back to decimal results in this number: 0.100000001490116119384765625. Add that number to itself ten times and you get approximately 1.0000000149011612. 

A fractional error, added and multiplied many times, can result in numbers being "off" enough to throw off what you want to measure.

What am I going to do about this?

I want, when feasible, to represent numbers as fractions when you enter them into an app that specifically uses fractions in its input, and/or output. When you enter a number like 3¼ into some of my apps, I will actually keep it as three numbers: 3, 1, and 4, and keep those values straight when we add, multiply, or perform other operations on them.

If I represent 0.1 as the fraction ¹/₁₀ , and add that number to itself ten times, should get ¹⁰/₁₀ , and that should compare to the number 1 as exactly equal.


I am using this technique in Sizeography's new iOS app: myGraph. Not just for additional precision, but also to allow the user interface to clearly reflect the user is thinking. If a user wants graph paper with cells that are 1/8 of an inch wide, or 8 cells per inch, that's easier for the user to think about than requiring the user to type in 0.125.



myGraph showing Grid Spacing as 1/8


myGraph represents traditional measures as inches, either in fractions like ¼ or decimals like 0.25. myGraph also works in the metric system using centimeters. Centimeters are only represented as decimals.

When you switch between inches and centimeters, myGraph will convert to the nearest approximately equal value. If you are using inches and swich from fractions to or from decimals, myGraph will convert to the nearest approximately equal value.


No comments:

Post a Comment