How hard can it be to write a simple four-function calculator program? After all, computers are good at math, and making a calculator isn’t exactly blazing a new trail, right? But [Chad Nauseam] will tell you that it is harder than you probably think. His post starts with a screenshot of the iOS calculator app with a mildly complex equation. The app’s answer is wrong. Android’s calculator does better on the same problem.
What follows is a bit of a history lesson and a bit of a math lesson combined. As you might realize, the inherent problem with computers and math isn’t that they aren’t good at it. Floating point numbers have a finite precision and this leads to problems, especially when you do operations that combine large and small numbers together.
Indeed, any floating point representation has a bigger infinity of numbers that it can’t represent than those that it can. But the same is true of a calculator. Think about how many digits you are willing to type in, and how many digits you want out. All you want is for each of them to be correct, and that’s a much smaller set of numbers.
Google’s developer, [Hans-J. Boehm] tackled this problem by turning to recursive real arithmetic (RRA). Here, each math function is told how accurate it needs to be, and a set of rules determines the highest required accuracy.
But every solution brings a problem. With RRA, there is no way to tell very small numbers from zero. So computing “1-1” might give you “0.000000000”, which is correct but upsetting because of all the excess precision. You could try to test if “0.00000000” was equal to “0”, and simplify the output. But testing for equality of two numbers in RRA is not guaranteed to terminate: you can tell if two numbers are unequal by going to more and more precision until you find a difference, but if the numbers happen to be equal, this procedure never ends.
The key realization for [Boehm] and his collaborators was that you could use RRA only for cases where you deal with inexact numbers. Most of the time, the Android calculator deals with rationals. However, when an operation produces a potentially irrational result, it switches to RRA for the approximation, which works because no finite representation ever gets it exactly right. The result is a system that doesn’t show excess precision, but correctly displays all of the digits that it does show.
We really like [Chad’s] step-by-step explanation. If you would rather dive into the math, you can read [Boehm’s] paper on the topic. If you ever wonder how many computer systems handle odd functions like sine and cosine, read about CORDIC. Or, avoid all of this and stick to your slide rule.
“Or, avoid all of this and stick to your slide rule.”
Swiping the small parts was common hazing.
The hardest part of writing a calculator app is coming up with enough bs updates that it isn’t removed from the app store. Thank you google /s
Calculator 2.1: Moved the zero over a pixel to the left
Calculator 2.2: Moved it back to the right. Aaaaand update
Isn’t that the truth?! Google’s “update it often, or get kicked out of the app store” mandate to app developers seems to cause more buggy apps.
[Chad Nauseam]’s linked blog entry(?) was a great read – thanks for that.
Very clear presentation of the potential solutions, the problems within each and the conclusion they finnaly arrived at.
I mean having studied math and comp-sci I pretty much knew all the basics – like floating point numbers not being able to represent all numbers or that working with very big and small numbers in floating point is a no-no – but I had no real idea how bad it really was/is.
Srsly – the “best” HaD article this year so far IMO.
Well, the real difficulty is most phones don’t have 4GB of RAM yet /s
Don’t they? Mine has 6 GB, and I got it 2 years ago for $350.
My mother used to run a shop and there ware many simple Casio calculators that had a function of rounding results to 2 (3 or 4 – depending on setting) digits after coma – this was used to mimic currency. Few times she run on calculations that made no sense but in fact were results of rounding. She understood what is the problem here but it’s hard to avoid it.
As for the calculators – why aren’t they using binary coded decimal? Everyday use of calculator is mostly up to few (less than 12) digits often related to money. It’s cool to have 32bit floating point but this should be reserved for more professional use. Of course we could have one app with toggle switch to define which coding we want but modern GUI requires to keep user far from any adjustments.
Why not used BCD? They used to. Floating point, by which I mean decimal point, BCD. All of the legendary HP Saturn calculators like the HP41 and HP15 did this. Many early mainframe computers also used BCD, because their first and primary purpose was to do business math and their output had to align with the accounts ledger. The move to pure binary seems to have been coincident with the introduction of 7400 series IC’s in the 1970’s, which made binary chunks of information much cheaper and more convenient to handle. There was a brief nod toward BCD, with early CPU’s having DAA instructions and count by 10 chips like the 7490, but once they started making binary ALU slices in single chip form factor it was all over.
That’s what I was taught in assembly language class (back when dinosaurs ruled the earth). Perhaps not the fastest way, but you can be as accurate as you want (within the bounds of your RAM). CORDIC for trig functions, of course.
BCD can’t represent an irrational number. You eventually need to do some rounding somewhere
FP can’t either. FP value is result of division if integer by integer – a rational by definition. Rather they have strict precision and cannot represent periodic rational values while FP can represent some of them.
TBH, if I’m recovering from a coma the number of digits my calculator displays is the LEAST of my worries.
A+1-A, right? We don’t take kindly to folks that don’t parse ’round here. I won’t ever know what the wrong answer was because life is too short to just be giving my eyeballs away in the videosphere. A properly written article would have mentioned it. Nuh guh duh, wouldn’t be prudent.
It’s right here in the top picture. Is life also too short to read the article you are reading?
“How hard can it be to write a simple four-function calculator program?”
Fairly simple.
“The app’s answer is wrong.”
Producing accurate results was not part of the original inquiry! You’re moving the goal posts. ;)
NumWorks does something similar, I believe: https://www.numworks.com/engineering/software/poincare/
Calculators must be built.on top of symbolic engines (e.g. calc in emacs).
Gnu “bc” has no problem with this.
BC is arbitrary precision I believe using GNI GMP.
But what about 10^100000000 + 1 – 10^100000000
?
It might be difficult to code the understanding of that expression as x + 1 – x.
It takes a bit, but still computes the correct result.
Is that Android calculator open source by any chance? Probably not part of AOSP…
Android one (and RealCalc) actually emulate HP/CASIO math (exact behaviour) which got FP with larger digit number than 64bit double. But even on those eventually get this problem.
Symbolic calculations are different. To begin with, they are million times slower than native and represent values as strings.
This isn’t a calculator problem. This is well known and well documented limitation of floating point math hence FP was standardized by IEEE. Hence in certain areas or for certain uses FP is explicitly prohibited -e.g. for calculating time, for navigation coordinates, etc.
“computing “1-1” might give you “0.000000000””
Those trailing zeros aren’t significant digits and should be removed.
Calculators round. That’s why you need to understand symbolic math and the limitations of calculators in order to use them properly. Some calculators use BCD with many digits which can help avoid problems with binary floating point numbers.
If you want a calculator not to round you need one that can do symbolic math. It’s called a match stack. Those would simplify the equation and result and can provide an exact result. But those are not basic calculators.
How hard? Well, ask Microsoft… How did they manage to make a calculator app in Windows 11 that is slower to load and is generally worse than what it used to have?
Calculators are just examples of the engineering lores surrounding building better mousetraps.
I looked into this (after replacing the new with the old), apparently it has to launch its own container due to being a UWP program. That’s what takes so long
But…. Why. Why the hell it’s UWP…
V41.
RPN for life!
@Antron Argaiv said: “RPN for life!”
Try Plus42 a very capable hp42S RPN calculator emulator that runs cross platform. See here:
https://thomasokken.com/plus42/
The Android and iOS versions of Plus42 are paid apps, but the Windows, MacOS, and Linux versions are free downloads. Any donations will help keep Plus42 going. You may donate any amount you wish, large or small. Donations are processed by PayPal.
Downloads: https://thomasokken.com/plus42/#downloads
Documentation: https://thomasokken.com/plus42/#doc
Frequently Asked Questions: https://thomasokken.com/plus42/#faq
Open the Win10/11 calculator app and put it in Standard mode.
Grab the left or right edge and start resizing the window.
Look at the intersection of the x^2, [sqrt], 8, and 9 keys.
If too small, take screenshots at various window sizes, paste in Paint, and zoom in on the intersection.
You’re welcome.
I worked in dev for many years and as a liaison between the business users and devs then later on and it’s shocking how simple people think it is to do when ends up being a very complex thing. A small business process can have many different iterations and permutations and the turnaround expected is so quick when it’s just like this calculator problem, or writing a calendar problem (there was a previous HaD article on that too that felt like it should’ve been an emotional support paper for devs), so Devs are left to take shortcuts like grab a library from here (and make sure it doesn’t use any outdated libraries with any CVEs in the chain and set up a notification for any updates and CVEs in said library). Half of my time I spent seeing if there was a boxed product already in existence for the issue or a popular updated library with paid support that might make the job possible in the 6-8 week timeframe most of the digitisation projects had.
I wrote the Panasonic Mobile phone calculator software around 1999/2000. I had no end of problems with floating point numbers and converting the numbers back in to strings to display on the monochrome dot matrix display. Despite my testing and the testing done by the systems test team there was still a corner case that was found after it had been released. My floating point precision was lacking and the calculation could be a factor of 10 out. Happy days and happy memories!
wow, this takes me back… in 1982 or 3 compiler class we had to write the compiler section to process encountered math assignments ( think x = string). It really forced me to think about ‘what are the rules’. Like learning Spanish, all the sudden you have a ton of realizations about how English works – where it does. We had to take the string after the assignment and create a series of assembler instructions that would yield the answer, and gracefully fail if there were errors ( div by zero…) . This was definitely one of the formative academic projects that shaped my view of and approach to programming.
I wonder if switching from the IEEE real number representation to posits could improve rounding problems in this application.
https://spectrum.ieee.org/floating-point-numbers-posits-processor
https://www.johndcook.com/blog/2018/04/11/anatomy-of-a-posit-number/
I wrote one over a few lunch breaks that could do exponents and operator precedence. The “UI” was just GNU readline but that was the main point of my project. I used a system that used a typed union that could use a double or pointer to a gnu MP Bignum (mpz_t). I originally wrote my own multiprecision and a Montgomery’s ladder for it, but the code easier to read when I switched to libgmp.
Do RPN calculators have this same problem? I don’t believe my old HP-25 Reverse Polish Notation calculator had a rounding problem. Haven’t used it in years so can’t test it to be sure.
it’s intrinsic to the operation itself, so yes. any time you add a very big number to a very small number, all fixed-precision systems will show this limit. the only perfect remedy is to use a variable precision that represents the addend completely. in practice, it doesn’t tend to matter in calculators — people just don’t do that very often. in fact they typically don’t use very large numbers at all, and accept that very small numbers tend to become rounding error. so some trivial fixed precision like 20 or 100 decimal places is “good enough for me”. but it does matter a lot in some algorithms.
a more specific way to solve this problem is to add and subtract your large numbers first before adding and subtracting the smaller numbers. 10 100 ^ 10 100 ^ – 1 +
Well, do it as in Math class… simplify, then calculate… wow the issue is gone off to the voids except well it might be complex in other parts and its not as easy as just brute forcing the hell out of an equation. I mean why did nobody except a single person in this comment section say that… And even that person got misunderstood. At least it would be a considerable approach, I’m not saying it’s feasible for non business needs.