tags:

views:

69

answers:

3

Let's say you want to convert from degrees to radians:

radians =  degrees * (pi / 180)

If pi is considered a constant for the purpose of this calculation, then the resulting radians value should have the same number of significant digits as the initial degrees. I.E.

-32.39    degrees = -0.5653 radians     # 4 significant digits
-32.38795 degrees = -0.5652763 radians  # 7 significant digits

I was surprised that I couldn't find any examples in any language of how to perform this seemingly simple operation.

My first thought is to:

degrees_str = degrees
# remove any non-significant leading zeros from degrees_str
# degree_digits = count the remaining digit characters in degrees_str
# radian_int_digits = count the digits in integer portion of the radians
# round radians to (degree_digits - radian_int_digits) digits after the decimal point

Is that the most efficient manner in performing this general type of calculation (not specific to degrees/radians)?

+2  A: 

The concept of significant digits doesn't have much value in computing, because the computer doesn't work in decimal digits. It's possible that the value -32.39 is stored internally in a way that makes it closer to -32.38999999999999 than to -32.39000000000000.

Mark Ransom
+4  A: 

Take a look at interval arithmetic.

Often when applied in computing, all operations are assumed to cause a widening of the interval by one unit in the last place, so it gives a pessimistic result.

The intervals can be set base on the known precisions of the inputs - if you have pi = 3.142, then you would make the pi constant the interval [3.1415, 3.1425].

The intervals can be set base on the known precisions of the inputs - if you have pi = 3.142, then you would make the pi constant the interval

Assuming 8 sig figs working for intervals - you need more precision in the interval than you have in the values,

pi = [3.1415000, 3.1425000].  // pi to 4sf

angle = [-32.385000, -32.395000]. // angle to 4sf

degs_to_rads = pi / 180 // exact constant 180
  = [0.017452776, 0.017458334]. // truncated and widened from [0.0174527778,0.0174583333]

rads = pi * angle / 180 
   = [-0.56556274,-0.56520814] // truncated and widened from [-0.56556273,-0.565208151]

width(rads) = abs(-0.56556274 - (-0.56520814)) = -0.0003546

so if you want to format rads to a whole number of sig fig, you chose the significant figures so that the error on the interval is not visible; in this case

sf  min             max
8   -0.56556274     -0.56520814
5   -0.56556        -0.56521 
4   -0.5656         -0.5652
3   -0.566          -0.565
2   -0.57           -0.57

So although the interval is quite small for inputs known to four significant figures, the result is only accurate to two.

This is similar to the common practice of quoting results to fewer significant digits than the inputs used, rather than the example you give which assumes perfect precision.

Pete Kirkham
I like this concept, didn't know it had a name. I would extend it to have a nominal value in addition to the minimum and maximum of the interval; it won't always be in the center of the interval.
Mark Ransom
@Mark it tends to get applied where the value is not known to infinite precision, so you don't know where the nominal value is in the interval to start with.
Pete Kirkham
(besides, many cpus only have 128 bit registers so can only operate on two doubles at a time http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.84.2642 )
Pete Kirkham
+3  A: 

Floating point arithmetic is complicated, as Mark Ransom's answer noted. If you are programming scientific or mathematical code, be sure to fully understand floating point arithmetic. Be sure you fully understand the IEEE format, including denormalized numbers, and furthermore, the common sources of loss of precision. Such as cancellation error and when/where IEEE numbers are rounded... and the concept of machine epsilon as well. There was an entire course on just this at my university... and I'm sure the field goes far deeper than that.

Basically, the IEEE Double Precision number stores 53-bits in the mantissa, which is kinda like 15.9-digits of precision... but not really, because the mantissa is in base-2 while saying "15.9 significant digits" implies base 10. (log(2^53) is ~15.9) Overall, the concept of significant digits is simply not useful when using IEEE Floating Point numbers. Its better to have a full understanding of floating point arithmetic if you want to maintain accuracy.

If you REALLY need to implement significant digits, do yourself a favor and avoid double-precision numbers. Store them as integers instead. You might have a chance with the Base-10 IEEE numbers, but only C++0x mentions them (and I don't know of any other programming languages that support decimal64 numbers yet)

Dragontamer5788
http://docs.sun.com/source/806-3568/ncg_goldberg.html provides useful info.
Alexandre C.
For Java, a good option would be to use the BigDecimal class, which allows you to work with much precision.
Luis Miguel
Oh yeah, I forgot about arbitrary precision libraries. In that same vein... using Mathematical software designed for this (such as MatLab or Mathematica) would also be a good option.
Dragontamer5788