aboutsummaryrefslogtreecommitdiff
path: root/2023/24
diff options
context:
space:
mode:
Diffstat (limited to '2023/24')
-rw-r--r--2023/24/24b.c49
1 files changed, 27 insertions, 22 deletions
diff --git a/2023/24/24b.c b/2023/24/24b.c
index 48b0a79..90e2e74 100644
--- a/2023/24/24b.c
+++ b/2023/24/24b.c
@@ -4,9 +4,12 @@ machine (ahah - doesn't work on my machine (: )
4However, with slightly different values for eps I got two answers whose 4However, with slightly different values for eps I got two answers whose
5difference was 4 and one was too high, the other too low. A quick binary 5difference was 4 and one was too high, the other too low. A quick binary
6search gave the correct result. 6search gave the correct result.
7I'll make a more stable version if I feel like it. EDIT: made slighly more 7I'll make a more stable version if I feel like it.
8numerically stable, now the result is actually correct (if rounded to the 8
9nearest integer). 9EDIT: made slighly more numerically stable, now the result is actually
10correct (if rounded to the nearest integer).
11
12EDIT: made numerical result even more accurate using long doubles.
10*/ 13*/
11 14
12#include <stdbool.h> 15#include <stdbool.h>
@@ -20,7 +23,8 @@ nearest integer).
20#define eps 1e-10 23#define eps 1e-10
21#define EQ(x,y) (ABS((x)-(y))<eps*(ABS(x)+ABS(y))) 24#define EQ(x,y) (ABS((x)-(y))<eps*(ABS(x)+ABS(y)))
22 25
23typedef struct { double x, y, z; } point_t; 26typedef long double num_t;
27typedef struct { num_t x, y, z; } point_t;
24typedef struct { point_t p, v; } line_t; 28typedef struct { point_t p, v; } line_t;
25 29
26char *buf, line[N]; 30char *buf, line[N];
@@ -30,9 +34,9 @@ line_t l[N];
30bool isnum(char c) { return (c >= '0' && c <= '9') || c == '-'; } 34bool isnum(char c) { return (c >= '0' && c <= '9') || c == '-'; }
31 35
32line_t readl(char *buf) { 36line_t readl(char *buf) {
33 double a[6]; 37 num_t a[6];
34 for (int i = 0; i < 6; i++) { 38 for (int i = 0; i < 6; i++) {
35 a[i] = (double)atoll(buf); 39 a[i] = (num_t)atoll(buf);
36 while (isnum(*buf)) buf++; 40 while (isnum(*buf)) buf++;
37 while (*buf != '\n' && !isnum(*buf)) buf++; 41 while (*buf != '\n' && !isnum(*buf)) buf++;
38 } 42 }
@@ -42,25 +46,25 @@ line_t readl(char *buf) {
42 }; 46 };
43} 47}
44 48
45void swap(double *x, double *y) { double aux = *x; *x = *y; *y = aux; } 49void swap(num_t *x, num_t *y) { num_t aux = *x; *x = *y; *y = aux; }
46 50
47void printa(double A[D][D], double C[D], int d) { 51void printa(num_t A[D][D], num_t C[D], int d) {
48 for (int i = 0; i < d; i++) { 52 for (int i = 0; i < d; i++) {
49 printf("[ "); 53 printf("[ ");
50 for (int j = 0; j < d; j++) 54 for (int j = 0; j < d; j++)
51 printf("%.2lf ", A[i][j]); 55 printf("%.2llf ", A[i][j]);
52 printf("]\t[%.2lf]\n", C[i]); 56 printf("]\t[%.2llf]\n", C[i]);
53 } 57 }
54} 58}
55 59
56/* Solve the linear system AX = C with row reduction */ 60/* Solve the linear system AX = C with row reduction */
57/* Return true if it has a unique solution, false in any other case */ 61/* Return true if it has a unique solution, false in any other case */
58bool solvesystem(double A[D][D], double C[D], int d, double *X) { 62bool solvesystem(num_t A[D][D], num_t C[D], int d, num_t *X) {
59 /* Row reduction */ 63 /* Row reduction */
60 for (int i = 0; i < d; i++) { 64 for (int i = 0; i < d; i++) {
61 /* Make first nonzero */ 65 /* Make first nonzero */
62 int imax; 66 int imax;
63 double maxi = 0.0; 67 num_t maxi = 0.0;
64 for (int j = i; j < d; j++) { 68 for (int j = i; j < d; j++) {
65 if (ABS(A[j][i]) > maxi) { 69 if (ABS(A[j][i]) > maxi) {
66 maxi = ABS(A[j][i]); 70 maxi = ABS(A[j][i]);
@@ -74,7 +78,7 @@ bool solvesystem(double A[D][D], double C[D], int d, double *X) {
74 78
75 /* Reduce rows */ 79 /* Reduce rows */
76 for (int ii = i+1; ii < d; ii++) { 80 for (int ii = i+1; ii < d; ii++) {
77 double r = A[ii][i] / A[i][i]; 81 num_t r = A[ii][i] / A[i][i];
78 for (int k = i; k < d; k++) 82 for (int k = i; k < d; k++)
79 A[ii][k] -= r*A[i][k]; 83 A[ii][k] -= r*A[i][k];
80 C[ii] -= r*C[i]; 84 C[ii] -= r*C[i];
@@ -92,7 +96,7 @@ bool solvesystem(double A[D][D], double C[D], int d, double *X) {
92 return true; 96 return true;
93} 97}
94 98
95point_t pos(line_t l, double t) { 99point_t pos(line_t l, num_t t) {
96 return (point_t) { 100 return (point_t) {
97 .x = l.p.x + t*l.v.x, 101 .x = l.p.x + t*l.v.x,
98 .y = l.p.y + t*l.v.y, 102 .y = l.p.y + t*l.v.y,
@@ -102,7 +106,7 @@ point_t pos(line_t l, double t) {
102 106
103void testsolution(line_t sol) { 107void testsolution(line_t sol) {
104 for (int i = 0; i < nlines; i++) { 108 for (int i = 0; i < nlines; i++) {
105 double t = -1.0; 109 num_t t = -1.0;
106 if (!EQ(sol.v.x, l[i].v.x)) 110 if (!EQ(sol.v.x, l[i].v.x))
107 t = (sol.p.x-l[i].p.x)/(l[i].v.x-sol.v.x); 111 t = (sol.p.x-l[i].p.x)/(l[i].v.x-sol.v.x);
108 if (!EQ(sol.v.y, l[i].v.y)) 112 if (!EQ(sol.v.y, l[i].v.y))
@@ -111,8 +115,9 @@ void testsolution(line_t sol) {
111 t = (sol.p.z-l[i].p.z)/(l[i].v.z-sol.v.z); 115 t = (sol.p.z-l[i].p.z)/(l[i].v.z-sol.v.z);
112 point_t p1 = pos(sol, t), p2 = pos(l[i], t); 116 point_t p1 = pos(sol, t), p2 = pos(l[i], t);
113 /* 117 /*
114 printf("Line %d intersected at t = %.2lf " 118 printf("Line %d intersected at t = %.2llf in "
115 "in (%.2lf, %.2lf, %.2lf) and (%.2lf, %.2lf, %.2lf)\n", 119 "(%.2llf, %.2llf, %.2llf) and "
120 "(%.2llf, %.2llf, %.2llf)\n",
116 i, t, p1.x, p1.y, p1.z, p2.x, p2.y, p2.z); 121 i, t, p1.x, p1.y, p1.z, p2.x, p2.y, p2.z);
117 */ 122 */
118 if (t < eps || 123 if (t < eps ||
@@ -152,7 +157,7 @@ int main() {
152 * one can shuffle the input file until it works. 157 * one can shuffle the input file until it works.
153 */ 158 */
154 int d = 6; 159 int d = 6;
155 double A[D][D] = { 160 num_t A[D][D] = {
156 /* First equation: lines 0 and 1, x and y only */ 161 /* First equation: lines 0 and 1, x and y only */
157 {l[0].v.y-l[1].v.y, l[1].v.x-l[0].v.x, 0.0, 162 {l[0].v.y-l[1].v.y, l[1].v.x-l[0].v.x, 0.0,
158 l[1].p.y-l[0].p.y, l[0].p.x-l[1].p.x, 0.0}, 163 l[1].p.y-l[0].p.y, l[0].p.x-l[1].p.x, 0.0},
@@ -172,7 +177,7 @@ int main() {
172 {0.0, l[0].v.z-l[2].v.z, l[2].v.y-l[0].v.y, 177 {0.0, l[0].v.z-l[2].v.z, l[2].v.y-l[0].v.y,
173 0.0, l[2].p.z-l[0].p.z, l[0].p.y-l[2].p.y}, 178 0.0, l[2].p.z-l[0].p.z, l[0].p.y-l[2].p.y},
174 }; 179 };
175 double C[D] = { 180 num_t C[D] = {
176 /* First equation: lines 0 and 1, x and y only */ 181 /* First equation: lines 0 and 1, x and y only */
177 l[1].p.y*l[1].v.x - l[1].p.x*l[1].v.y 182 l[1].p.y*l[1].v.x - l[1].p.x*l[1].v.y
178 - l[0].p.y*l[0].v.x + l[0].p.x*l[0].v.y, 183 - l[0].p.y*l[0].v.x + l[0].p.x*l[0].v.y,
@@ -192,7 +197,7 @@ int main() {
192 l[2].p.z*l[2].v.y - l[2].p.y*l[2].v.z 197 l[2].p.z*l[2].v.y - l[2].p.y*l[2].v.z
193 - l[0].p.z*l[0].v.y + l[0].p.y*l[0].v.z, 198 - l[0].p.z*l[0].v.y + l[0].p.y*l[0].v.z,
194 }; 199 };
195 double X[d]; 200 num_t X[d];
196 if (!solvesystem(A, C, d, X)) { 201 if (!solvesystem(A, C, d, X)) {
197 printf("No unique solution, shuffle input and try again.\n"); 202 printf("No unique solution, shuffle input and try again.\n");
198 exit(1); 203 exit(1);
@@ -204,8 +209,8 @@ int main() {
204 }; 209 };
205 testsolution(sol); 210 testsolution(sol);
206 211
207 printf("p = (%.2lf, %.2lf, %.2lf), v = (%.2lf, %.2lf, %.2lf)\n", 212 printf("p = (%.2llf, %.2llf, %.2llf), v = (%.2llf, %.2llf, %.2llf)\n",
208 sol.p.x, sol.p.y, sol.p.z, sol.v.x, sol.v.y, sol.v.z); 213 sol.p.x, sol.p.y, sol.p.z, sol.v.x, sol.v.y, sol.v.z);
209 printf("%lf\n", sol.p.x + sol.p.y + sol.p.z); 214 printf("%llf\n", sol.p.x + sol.p.y + sol.p.z);
210 return 0; 215 return 0;
211} 216}

Generated with cgit - Back to sebastiano.tronto.net