How is it that ฯ€ and ฯ€ / 10 have the same relative error if they are represented as binary64?

Suppose you quickly want to determine which of ฯ€ or ฯ€ / 10 has the largest relative error if it is presented in IEEE 754 binary format. In addition, you only have the C compiler.

You can write a C program below or a more compact version:

#include <stdio.h> #include <math.h> volatile long double pil = 3.14159265358979323846L; volatile double pi = 3.14159265358979323846; volatile long double tpil = 0.314159265358979323846L; volatile double tpi = 0.314159265358979323846; int main() { volatile long double abs = pil - pi; printf("%La\n%La\n%La\n", pil, (long double)pi, abs); printf("pi: abs err %La -> rel %La\n", abs, abs / pil); volatile long double abst = tpil - tpi; printf("pi/10: abs err %La -> rel %La\n", abst, abst / tpil); } 

The funny thing is that this program shows that the relative errors ฯ€ and ฯ€ / 10 are identical:

  0xc.90fdaa22168c235p-2
 0xc.90fdaa22168cp-2
 0x8.d4p-56
 pi: abs err 0x8.d4p-56 -> rel 0xb.3d85789395e215bp-58
 pi / 10: abs err 0xe.2p-60 -> rel 0xb.3d85789395e215bp-58

I added volatile qualifiers and intermediate calculations to look at the generated assembly and make sure that this is not a compiler error. This is apparently not the case.

This is strange because many other values โ€‹โ€‹of v do not have the property that the relative error v coincides with the relative error v / 10. I checked with 0.1 and 0.3. Also, this is not a matter of magnitude, because 3 and 3.5 obviously have different relative errors than their corresponding tenths. Although 5, 10, 15, ... have the same relative error as their corresponding tenths, they should be considered as exceptions.

Now the program does not calculate the exact values โ€‹โ€‹of relative errors. It can contain only 12 bits (one sign bit plus 11 bits of the difference between a 64-bit value and a 53-bit value). Thus, it was possible a priori something like one case in 4096, when the absolute error ฯ€ was obtained as a 10-fold absolute error ฯ€ / 10.

This still seems an unlikely coincidence. Was there an a priori case that a real constant, taken between 3 and 3.5, had the same relative error as its tenth, if it is represented as double more than my intuition says that it should be? Or is there another way to see this, for example, "it happens as soon as the (double) (ฯ€ / 10) value has enough finite zeros to multiply by ten to be exact", which seems much more frequent (close to 1/8 )?

+6
source share
1 answer

The best way to look at this question is to notice that the double value of the nearest ฯ€ is a multiple of 5:

 #include <stdio.h> #include <math.h> #include <stdint.h> #include <inttypes.h> #include <string.h> volatile long double pil = 3.14159265358979323846L; volatile double pi = 3.14159265358979323846; volatile long double tpil = 0.314159265358979323846L; volatile double tpi = 0.314159265358979323846; void print_significand(double d) { uint64_t significand; memcpy(&significand, &d, 8); significand &= ((uint64_t)1<<52) - 1; significand |= (uint64_t)1<<52; printf("%" PRIx64 " %" PRIu64 "\n", significand, significand); } int main() { printf("Significand of (double)pi: "); print_significand(pi); printf("Significand of (double)(pi/10): "); print_significand(tpi); โ€ฆ 

It shows:

  Significand of (double) pi: 1921fb54442d18 7074237752028440
 Significand of (double) (pi / 10): 141b2f769cf0e0 5659390201622752

The integer 5659390201622752 is exactly 7074237752028440/5 * 4. Multiplication by four is used to save the double representing ฯ€ / 10, normalized.

Thus, for an arbitrary real r, chosen evenly between 2 and 4, approximated by the nearest double d , in five cases there is one chance that the value of d multiple of 5. When this happens, d/10.0 is accurate. This makes d/10.0 very good candidate for the name "double closest to r / 10".

How good is the candidate?

If dividing by 10 leads us from the top of the binad (just below 4) to the bottom of the binad (just above 0.25), then the representable doubles are relatively less dense around r / 10 than they are around r, and there is no way to find a closer double value to r / 10 than d/10.0 .

If dividing by 10 takes us from the bottom of the binad (just above 2) to the top of the binad (just below 0.25), then it doubles relatively tight around r / 10 than they around r. There is a possibility that there is a better double approximation for r / 10 than d/10.0 , especially if d already a bad approximation for r.

Cutoff point 2.5 . The real ฯ€ is above this cutoff point, therefore, knowing that the value of its double approximation was divisible by 5, it was enough to conclude that ฯ€ / 10 would be approximated by the tenth approximation ฯ€, and the relative errors of both approximations would be the same.

+6
source

Source: https://habr.com/ru/post/977930/


All Articles