Files
2025-02-Numerical/hws/hw1/main.c
2025-09-12 22:36:10 +09:00

176 lines
4.2 KiB
C

#include "nr.h"
#include <stdio.h>
#include <math.h>
void get_eps(float *eps) {
*eps = 1.0f;
while ((1.0f + *eps / 2.0f) > 1.0f) {
*eps /= 2.0f;
}
}
void get_eps_double(double *eps) {
*eps = 1.0;
while ((1.0 + *eps / 2.0) > 1.0) {
*eps /= 2.0;
}
}
#define CONV(i) ((double) (i))
void machar_double(int *ibeta, int *it, int *irnd, int *ngrd, int *machep, int *negep, int *iexp, int *minexp, int *maxexp,
double *eps, double *epsneg, double *xmin, double *xmax) {
int i, itemp, iz, j, k, mx, nxres;
double a, b, beta, betah, betain, one, t, temp, temp1, tempa, two, y, z, zero;
one = CONV(1);
two = one + one;
zero = one - one;
a = one;
do {
a += a;
temp = a + one;
temp1 = temp - a;
} while (temp1 - one == zero);
b = one;
do {
b += b;
temp = a + b;
itemp = (int) (temp - a);
} while (itemp == 0);
*ibeta = itemp;
beta = CONV(*ibeta);
*it = 0;
b = one;
do {
++(*it);
b *= beta;
temp = b + one;
temp1 = temp - b;
} while (temp1 - one == zero);
*irnd = 0;
betah = beta / two;
temp = a + betah;
if (temp - a != zero) *irnd = 1;
tempa = a + beta;
temp = tempa + betah;
if (*irnd == 0 && temp - tempa != zero) *irnd = 2;
*negep = (*it) + 3;
betain = one / beta;
a = one;
for (i = 1; i <= (*negep); i++) a *= betain;
b = a;
for (;;) {
temp = one - a;
if (temp - one != zero) break;
a *= beta;
--(*negep);
}
*negep = -(*negep);
*epsneg = a;
*machep = -(*it) - 3;
a = b;
for (;;) {
temp = one + a;
if (temp - one != zero) break;
a *= beta;
++(*machep);
}
*eps = a;
*ngrd = 0;
temp = one + (*eps);
if (*irnd == 0 && temp * one - one != zero) *ngrd = 1;
i = 0;
k = 1;
z = betain;
t = one + (*eps);
nxres = 0;
for (;;) {
y = z;
z = y * y;
a = z * one;
temp = z * t;
if (a + a == zero || fabs(z) >= y) break;
temp1 = temp * betain;
if (temp1 * beta == z) break;
++i;
k += k;
}
if (*ibeta != 10) {
*iexp = i + 1;
mx = k + k;
} else {
*iexp = 2;
iz = (*ibeta);
while (k >= iz) {
iz *= *ibeta;
++(*iexp);
}
mx = iz + iz - 1;
}
for (;;) {
*xmin = y;
y *= betain;
a = y * one;
temp = y * t;
if (a + a != zero && fabs(y) < *xmin) {
++k;
temp1 = temp * betain;
if (temp1 * beta == y && temp != y) {
nxres = 3;
*xmin = y;
break;
}
} else
break;
}
*minexp = -k;
if (mx <= k + k - 3 && *ibeta != 10) {
mx += mx;
++(*iexp);
}
*maxexp = mx + (*minexp);
*irnd += nxres;
if (*irnd >= 2) *maxexp -= 2;
i = (*maxexp) + (*minexp);
if (*ibeta == 2 && !i) --(*maxexp);
if (i > 20) --(*maxexp);
if (a != y) *maxexp -= 2;
*xmax = one - (*epsneg);
if ((*xmax) * one != *xmax) *xmax = one - beta * (*epsneg);
*xmax /= (*xmin * beta * beta * beta);
i = (*maxexp) + (*minexp) + 3;
for (j = 1; j <= i; j++) {
if (*ibeta == 2) *xmax += *xmax;
else
*xmax *= beta;
}
}
#undef CONV
int main() {
int ibeta, it, irnd, ngrd, machep, negep, iexp, minexp, maxexp;
float eps, epsneg, xmin, xmax;
machar(&ibeta, &it, &irnd, &ngrd, &machep, &negep, &iexp, &minexp, &maxexp,
&eps, &epsneg, &xmin, &xmax);
printf("Machine Accuracy for float (machar): \t\t%0.20f\n", eps);
get_eps(&eps);
printf("Machine Accuracy for float (get_eps): \t\t%0.20f\n", eps);
double eps_double, epsneg_double, xmin_double, xmax_double;
machar_double(&ibeta, &it, &irnd, &ngrd, &machep, &negep, &iexp, &minexp, &maxexp,
&eps_double, &epsneg_double, &xmin_double, &xmax_double);
printf("Machine Accuracy for double (machar_double): \t%0.20f\n", eps_double);
get_eps_double(&eps_double);
printf("Machine Accuracy for double (get_eps_double): \t%0.20f\n", eps_double);
return 0;
}