0

I have radian value of double data type x.

x = 0.423438990337458964763328594926861114799976348876953125;

When converting this value to degrees then back to radians, I expect the computer to give me the same value of x without losing precision.

I am using the qRadiansToDegrees method in qt and it seems perfect, but I still lose precision when trying to access the value of x.

If this is fixable, can somebody please tell me how to prevent this from occurring? If it isn't, is there another way to represent doubles so that they don't lose precision after converting?

Telescope
  • 2,068
  • 1
  • 5
  • 22
user9995
  • 21
  • 1

2 Answers2

7

In computing, a double can hold 53 significant digits in binary which translates to math.log(2**53, 10) ~= 15 significant digits in the decimal system we use.

Thus you cannot expect 0.423438990337458964763328594926861114799976348876953125, which has 54 significant digits, to be represented accurately.

If you really need this amount of precision there are separate libraries for handling high-precision numbers. However these are slower and likely not necessary.

xjcl
  • 12,848
  • 6
  • 67
  • 89
  • 1
    @JesperJuhl How many of those branches call such arbitrary precision numbers "double"s? Everyone knows exactly what this answer is saying, using clear and commonplace terminology. I don't think it's in any way ambiguous or hard to understand. – Asteroids With Wings Jul 02 '20 at 21:14
  • 1
    Well, *that* particular value [can](https://wandbox.org/permlink/TzhsKkSqACgLV716) be represented exactly (and it's not an accident, I assume). – Bob__ Jul 02 '20 at 21:21
  • 1
    @Bob__ My bad -- it seems these particular 54 digits can be represented exactly, but only 15 of those are guaranteed actual precision, the other 39 are "pseudo-precision". Those can get lost during arithmetic. – xjcl Jul 02 '20 at 22:13
  • Although funnily enough I just tried it in Python and get back the same result (`x == x * (pi / 360) * (360 / pi)`, also see `'{0:.60f}'.format(x)`). Not sure what is going on with OP. – xjcl Jul 02 '20 at 22:16
  • @xjcl I wouldn't expect `(pi / 360) * (360 / pi)` to produce any actual code; it trivially cancels out. – Asteroids With Wings Jul 03 '20 at 09:46
  • @AsteroidsWithWings Well, same result if you divide it into two statements `y = x * (pi / 360); x == y * (360 / pi)` – xjcl Jul 12 '20 at 13:34
  • @xjcl Yes, same story. Compilers don't just translate each line of code one at a time. They "understand" your algorithm and produce a real program matching those semantics, in efficient code targeted at your computer's platform. You're just writing an abstraction. – Asteroids With Wings Jul 12 '20 at 18:42
  • @AsteroidsWithWings But I did it an interpreted (REPL) session – xjcl Jul 12 '20 at 19:05
  • @xjcl That can be different then – Asteroids With Wings Jul 12 '20 at 19:05
0

x = 0.423438990337458964763328594926861114799976348876953125

That particular value happens to be exactly representable as an IEEE-754 double(1). We can find out its closest neighbourgs with a little snippet.

0.4234389903374589092521773636690340936183929443359375
0.423438990337458964763328594926861114799976348876953125
0.42343899033745902027447982618468813598155975341796875

Note that a value like 0.423438990337459 it's not exactly representable by a double and will be internally approximated by one of those(2). Also note that their relative "distance" is around 10-16.

In general, it's always possible to obtain the exact base 10 representation (with a maybe big, but finite number of decimal digits) of a floating point value with radix 2. The inverse is in general not possible (you'll need an inifinite number of bits to represent 0.1). I suspect the OP obtained this value by inspecting a particular double using a debugger.

When converting this value to degrees then back to radians, I expect the computer to give me the same value of x without losing precision.

I don't know how qRadiansToDegrees is implemented in Qt, nor what architecture the OP are using, but when I tried a possible implementation of this round trip I was lucky (see e.g. the first result here).

In general you should lower your expectations, I'm afraid, considering that a floating point multiplication is not even associative.

Here I tried to test the percentage of failures with random angles. It's around 25% in that testing environment.


1) The C++ Standard doesn't mandate the IEEE-754 standard for representing floating point values. The point of this answer, though, is that any fixed-sized representation can't possibly guarantee what the OP is expecting.

2) Some architectures may provide a wider precision (like 80-bits) for registers, so that intermediate results and calculations in general can be more accurate. This is just an example.

Bob__
  • 12,361
  • 3
  • 28
  • 42