For hyper-precision, the OP has 2 problems:
multiplying d by n and preserving greater precision than double . This answers in the first part below.
Execution of the mod period. A simple solution is to use degrees, and then mod 360 , it is easy enough to make accurate. Making 2*Ο large angles is difficult because it requires a 2*Ο value with approximately 27 accuracy points than (double) 2.0 * M_PI
Use 2 double to represent d .
Suppose 32-bit int and binary64 double . So double has 53-bit precision.
0 <= n <= 158,760,000 , which is about 2 27.2 . Since double can process unsigned 53-bit integers continuously and accurately, 53-28 β 25, any double with only 25 significant bits can be multiplied by n and still be accurate.
Segment d in 2 double dmsb,dlsb , 25 most significant digits and 28 least.
int exp; double dmsb = frexp(d, &exp);
Then each multiplication (or sequential addition) of dmsb*n will be exact. (This is an important part.) dlsb*n will be an error only in the smallest quantities.
double next() { d_sum_msb += dmsb; // exact d_sum_lsb += dlsb; double angle = fmod(d_sum_msb, M_PI*2); // exact angle += fmod(d_sum_lsb, M_PI*2); return sin(angle); }
Note: fmod(x,y) results are expected to be accurate, giving exact x,y .
#include <stdio.h> #include <math.h> #define AS_n 158760000 double AS_d = 300000006.7846112 / AS_n; double AS_d_sum_msb = 0.0; double AS_d_sum_lsb = 0.0; double AS_dmsb = 0.0; double AS_dlsb = 0.0; double next() { AS_d_sum_msb += AS_dmsb; // exact AS_d_sum_lsb += AS_dlsb; double angle = fmod(AS_d_sum_msb, M_PI * 2); // exact angle += fmod(AS_d_sum_lsb, M_PI * 2); return sin(angle); } #define POW2_25 (1U << 25) int main(void) { int exp; AS_dmsb = frexp(AS_d, &exp); // exact result AS_dmsb = floor(AS_dmsb * POW2_25); // exact result AS_dmsb /= POW2_25; // exact result AS_dmsb *= pow(2, exp); // exact result AS_dlsb = AS_d - AS_dmsb; // exact result double y; for (long i = 0; i < AS_n; i++) y = next(); printf("%.20f\n", y); }
Exit
0.04630942695385031893
Use degrees
We recommend using degrees as 360 degrees - this is the exact period and M_PI*2 radians is an approximation. C cannot represent Ο exactly.
If the OP still wants to use radians, for a further understanding of the execution of the Ο mode see Good for the last bit