If wrote a program in C to get a feel for the magnitude of floating point error with respect to repeated division.
#include <stdio.h>
int main (int argc, char* argv[]) {
if (argc < 3) {
printf("Enter a decimal number as the first positional "
"argument\n");
printf("Enter the maximum number of digits to print as the "
"second positional argument\n");
return 0;
}
long double d;
sscanf(argv[1], "%Lf", &d);
int m;
sscanf(argv[2], "%d", &m);
int i;
char format[10];
for (i = 1; i <= m; ++i) {
printf("(%d digits)\n", i);
sprintf(format, "%%.%dLf\n\n", i);
printf(format, d);
}
long double p = d;
printf("\n");
for (i = 1; i <= m; ++i) {
printf("(%Lf/10e%d with %d digits)\n", d, i, m);
p = p/(long double)10.0;
printf(format, p);
}
return 0;
}
This is one line of the output when run with the following arguments
$ fpe 0.1 700
.
.
.
(0.100000/10e180 with 700 digits)
0.0000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000999999999999999999969819570700939858153376
736698732853283605408116087882762948991724868957176649769045358705872354052
261113540314114885779914335315639806061208847920179776799404948795506248532
485303630811119507604985596684233990126219304092175565232198569923253737561
276484626462077772036038845251286782974821021132356946292172207615386395848
331484216638642723800290357587296443408362280895970909637712494349003491485
594533190659822910753768473307578901199121901299804449081420898437500000000
000000000000000000000000000
.
.
.
Here we observe 485 digits of floating point noise. This was compiled with gcc 4.4.3, which I’m assuming is using 80bit extended precision. However, 485 decimal digits is way more than 80 bits of information. So, my question is, where is this information coming from?
There is no extra information printed. The value printed is exactly the value of
p.After 180 iterations,
pis +0x1.A8E90F9908E0CA56p-602, which is 15309010345804195115•2-665. The IEEE 754 standard defines the value of a floating-point number to be a sign (+1 or −1) multiplied by an integer power of two (determined by the exponent field of the number) multiplied by the value of its significand (the fraction portion). So every floating-point number has a specific value. The above is the value ofp. In decimal, that value is exactly .9999999999999999999698195707009398581533767366987328532836054081160878827629489917248689571766497690453587058723540522611135403141148857799143353156398060612088479201797767994049487955062485324853036308111195076049855966842339901262193040921755652321985699232537375612764846264620777720360388452512867829748210211323569462921722076153863958483314842166386427238002903575872964434083622808959709096377124943490034914855945331906598229107537684733075789011991219012998044490814208984375•10-181.That is the value produced by your program. So, your output formatter has printed exactly the value of
p. It did a great job.In fact, all around, floating-point did a great job. That value is the long double value that is closest to 10-181. It is impossible to get any closer in a long double. So, even after hundreds of arithmetic operations, the errors did not grow.
There is no new information here. If we were told the bits that were in the representation of
p, we could have produced the same hundreds of decimal digits. They do not tell you anything new. However, they are also not garbage; they are exactly determined by the value ofp.