0

I want my cake and to eat it. I want to beautify (round) numbers to the largest extent possible without compromising accuracy for other calculations. I'm using doubles in C# (with some string conversion manipulation too).

Here's the issue. I understand the inherent limitations in double number representation (so please don't explain that). HOWEVER, I want to round the number in some way to appear aesthetically pleasing to the end user (I am making a calculator). The problem is rounding by X significant digits works in one case, but not in the other, whilst rounding by decimal place works in the other, but not the first case.

Observe:

  • CASE A: Math.Sin(Math.Pi) = 0.000000000000000122460635382238
  • CASE B: 0.000000000000001/3 = 0.000000000000000333333333333333

For the first case, I want to round by DECIMAL PLACES. That would give me the nice neat zero I'm looking for. Rounding by Sig digits would mean I would keep the erroneous digits too.

However for the second case, I want to round by SIGNIFICANT DIGITS, as I would lose tons of accuracy if I rounded merely by decimal places.

Is there a general way I can cater to both types of calculation?

phuclv
  • 37,963
  • 15
  • 156
  • 475
Dan W
  • 3,520
  • 7
  • 42
  • 69
  • I suggest you go learn about scientific notation. Any user who would be using this kind of math will know it, and it's intended for these ridiculously large and small numbers. – Logarr Jul 18 '13 at 13:35
  • I know about scientific notation. I used the full digit representation like this to make it arguably simpler to look at and think about the problem. – Dan W Jul 18 '13 at 13:45
  • "That would give me the nice neat zero I'm looking for." - That's not thinking about the problem in the scope of scientific notation. The formatting problem is pretty straightforward; you need to convert to SN, and then do a standard rounding based on decimal places. Basically what I'm saying is, don't try and re-invent the calculator. – Logarr Jul 18 '13 at 13:49
  • 2
    Showing those figures as SN would make no difference to the core of the question whatsoever. Rounding by decimal places would not work as well for CASE B where all the trailing 3s are valid and not erroneous unlike the last digits in case A. Please see the answer below by Sten for more info. – Dan W Jul 18 '13 at 14:00

3 Answers3

1

I don't thinks it's feasible to do that to the result itself and precision has nothing to do with it.

Consider this input: (1+3)/2^3 . You can "beautify" it by showing the result as sin(30) or cos(60) or 1/2 and a whole lot of other interpretations. Choosing the wrong "beautification" can mislead your user, making them think their function has something to do with sin(x).

If your calculator keeps all the initial input as variables you could keep all the operations postponed until you need the result and then make sure you simplify the result until it matches your needs. And you'll need to consider using rational numbers, e, Pi and other irrational numbers may not be as easy to deal with.

Sten Petrov
  • 10,943
  • 1
  • 41
  • 61
  • I'm guessing I'd need to check whether calcs have Pi, or e etc. in them, and then act accordingly. For more involved calcs with exponents, transcendental numbers, tiny numbers with lots of zeroes, and trig flying all over the place, I can see this getting really, really messy :( – Dan W Jul 18 '13 at 13:03
  • I wouldn't say "messy", I'd say "almost impossible" to get it right, and by the time you're done you'll have to sell your software for $1000/box :) – Sten Petrov Jul 18 '13 at 13:05
  • Wow, didn't realize it was going to be THAT hard. I wonder if anything out there can cope with this kind of thing. – Dan W Jul 18 '13 at 13:06
  • Try Mathlab or WolframAlpha.com – Sten Petrov Jul 18 '13 at 13:13
  • If you're looking at a general scientific calculator - yes, I'd say it's that hard. Make that a simple office calculator and stick to rational numbers - that's feasible, all you need is a fraction simplification routine, an RPN parser and some heuristics on when to stop executing operations and when to switch alternative operands – Sten Petrov Jul 18 '13 at 13:16
1

The best solution to this is to keep every bit you can get during calculations, and leave the display format up to the end user. The user should have some idea how many significant digits make sense in their situation, given both the nature of the calculations and the use of the result.

Default to a reasonable number of significant digits for a few calculations in the floating point format you are using internally - about 12 if you are using double. If the user changes the format, immediately redisplay in the new format.

Patricia Shanahan
  • 25,849
  • 4
  • 38
  • 75
  • I want it to be automatically determined according to the context. For example, if the user chooses 8 sig digits, then for case B, 0.00000000000000033333333 will result which is good! However case A will be 0.00000000000000012246064, which is bad as we instead want a result of zero. I don't want the user to be constantly switching between using SD and DP, according to the type of sum. – Dan W Jul 18 '13 at 16:07
  • You can always let the user specify a smallest magnitude to treat as non-zero. – Patricia Shanahan Jul 18 '13 at 22:12
1

The best solution is to use arbitrary-precision and/or symbolic arithmetic, although these result in much more complex code and slower speed. But since performance isn't important for a calculator (in case of a button calculator and not the one that you enter expressions to calculate) you can use them without issue

Anyway there's a good trade-off which is to use decimal floating point. You'll need to limit the input/output precision but use a higher precision for the internal representation so that you can discard values very close to zero like the sin case above. For better results you could detect some edge cases such as sine/cosine of 45 degree's multiples... and directly return the exact result.

Edit: just found a good solution but haven't had an opportunity to try.

Here’s something I bet you never think about, and for good reason: how are floating-point numbers rendered as text strings? This is a surprisingly tough problem, but it’s been regarded as essentially solved since about 1990.

Prior to Steele and White’s "How to print floating-point numbers accurately", implementations of printf and similar rendering functions did their best to render floating point numbers, but there was wide variation in how well they behaved. A number such as 1.3 might be rendered as 1.29999999, for instance, or if a number was put through a feedback loop of being written out and its written representation read back, each successive result could drift further and further away from the original.

...

In 2010, Florian Loitsch published a wonderful paper in PLDI, "Printing floating-point numbers quickly and accurately with integers", which represents the biggest step in this field in 20 years: he mostly figured out how to use machine integers to perform accurate rendering! Why do I say "mostly"? Because although Loitsch's "Grisu3" algorithm is very fast, it gives up on about 0.5% of numbers, in which case you have to fall back to Dragon4 or a derivative

Here be dragons: advances in problems you didn’t even know you had

Community
  • 1
  • 1
phuclv
  • 37,963
  • 15
  • 156
  • 475