Skip to content

Commit e7f7429

Browse files
author
XuhuaHuang
committed
Large Integer Multiplication
1 parent b4eb06e commit e7f7429

File tree

1 file changed

+245
-0
lines changed

1 file changed

+245
-0
lines changed
Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
/**
2+
* @file large_integer_multiplication.c
3+
* @author Xuhua Huang
4+
* @brief Demonstrates large integer multiplication via recursive decomposition,
5+
* delegating sub-multiplications to a child process over a pair of pipes.
6+
*
7+
* Usage: ./large_mul <a> <b> (both values must be in [1000, 9999])
8+
*
9+
* @version 0.1
10+
* @date 2026-02-20
11+
*
12+
* @copyright Copyright (c) 2026
13+
*
14+
*/
15+
16+
#include <stdio.h>
17+
#include <stdlib.h>
18+
#include <string.h>
19+
#include <sys/wait.h>
20+
#include <unistd.h>
21+
22+
/**
23+
* @brief Signed 64-bit integer for intermediate values
24+
*/
25+
typedef long long ll_t;
26+
27+
/* A simple two-element message sent across either pipe. */
28+
typedef struct {
29+
ll_t x;
30+
ll_t y;
31+
} pair_t;
32+
33+
/**
34+
* @brief Write a pair_t struct atomically to a file descriptor.
35+
*
36+
* @param fd The file descriptor to write to.
37+
* @param p The pair_t struct to write.
38+
* @return int 0 on success, -1 on failure
39+
*/
40+
static int write_pair(int fd, pair_t p) {
41+
// `write` may not write all bytes in one call, but for small structs it is atomic on pipes.
42+
// it returns the number of bytes actually written, which may be less than sizeof(pair_t) if an error occurs.
43+
ssize_t n = write(fd, &p, sizeof(pair_t));
44+
if (n != (ssize_t)sizeof(pair_t)) {
45+
perror("write_pair: write");
46+
return -1;
47+
}
48+
return 0;
49+
}
50+
51+
/**
52+
* @brief Read a pair_t struct atomically from a file descriptor.
53+
*
54+
* @param fd The file descriptor to read from.
55+
* @param p The pair_t struct to store the read values.
56+
* @return int 0 on success, -1 on failure
57+
*/
58+
static int read_pair(int fd, pair_t* p) {
59+
ssize_t n = read(fd, p, sizeof(pair_t));
60+
if (n != (ssize_t)sizeof(pair_t)) {
61+
perror("read_pair: read");
62+
return -1;
63+
}
64+
return 0;
65+
}
66+
67+
/**
68+
* @brief Write a signed 64-bit integer atomically to a file descriptor.
69+
*
70+
* @param fd The file descriptor to write to.
71+
* @param v The value to write.
72+
* @return int 0 on success, -1 on failure
73+
*/
74+
static int write_ll(int fd, ll_t v) {
75+
ssize_t n = write(fd, &v, sizeof(ll_t));
76+
if (n != (ssize_t)sizeof(ll_t)) {
77+
perror("write_ll: write");
78+
return -1;
79+
}
80+
return 0;
81+
}
82+
83+
/**
84+
* @brief Read a signed 64-bit integer atomically from a file descriptor.
85+
*
86+
* @param fd The file descriptor to read from.
87+
* @param v The point to store the read value in.
88+
* @return int 0 on success, -1 on failure
89+
*/
90+
static int read_ll(int fd, ll_t* v) {
91+
ssize_t n = read(fd, v, sizeof(ll_t));
92+
if (n != (ssize_t)sizeof(ll_t)) {
93+
perror("read_ll: read");
94+
return -1;
95+
}
96+
return 0;
97+
}
98+
99+
/**
100+
* @brief The child waits for four pair_t messages, multiplies each pair, and
101+
* returns the ll_t result back to the parent. After the fourth result it
102+
* closes its pipe ends and exits cleanly.
103+
*
104+
* @param pipe_in read-end of the parent to child pipe
105+
* @param pipe_out write-end of the child to parent pipe
106+
*/
107+
static void run_child(int pipe_in, int pipe_out) {
108+
for (int i = 0; i < 4; ++i) {
109+
pair_t operands;
110+
if (read_pair(pipe_in, &operands) != 0) {
111+
fprintf(stderr, "child: failed to read operands (round %d)\n", i + 1);
112+
exit(EXIT_FAILURE);
113+
}
114+
115+
ll_t product = operands.x * operands.y;
116+
117+
printf("[child] round %d: %lld * %lld = %lld\n", i + 1, operands.x, operands.y, product);
118+
fflush(stdout);
119+
120+
if (write_ll(pipe_out, product) != 0) {
121+
fprintf(stderr, "child: failed to write result (round %d)\n", i + 1);
122+
exit(EXIT_FAILURE);
123+
}
124+
}
125+
126+
close(pipe_in);
127+
close(pipe_out);
128+
exit(EXIT_SUCCESS);
129+
}
130+
131+
static ll_t send_and_receive(int pipe_out, int pipe_in, ll_t x, ll_t y) {
132+
pair_t job = {x, y};
133+
if (write_pair(pipe_out, job) != 0) {
134+
fprintf(stderr, "parent: failed to send job (%lld, %lld)\n", x, y);
135+
exit(EXIT_FAILURE);
136+
}
137+
138+
ll_t result = 0;
139+
if (read_ll(pipe_in, &result) != 0) {
140+
fprintf(stderr, "parent: failed to read result for (%lld, %lld)\n", x, y);
141+
exit(EXIT_FAILURE);
142+
}
143+
return result;
144+
}
145+
146+
int main(int argc, char* argv[]) {
147+
/* --- Argument validation ------------------------------------------ */
148+
if (argc != 3) {
149+
fprintf(stderr, "Usage: %s <a> <b>\n", argv[0]);
150+
fprintf(stderr, " Both arguments must be integers in the range [1000, 9999].\n");
151+
return EXIT_FAILURE;
152+
}
153+
154+
char *end_ptr_a = NULL, *end_ptr_b = NULL;
155+
ll_t a = strtoll(argv[1], &end_ptr_a, 10);
156+
ll_t b = strtoll(argv[2], &end_ptr_b, 10);
157+
158+
if (*end_ptr_a != '\0' || *end_ptr_b != '\0') {
159+
fprintf(stderr, "Error: non-numeric input detected.\n");
160+
return EXIT_FAILURE;
161+
}
162+
if (a < 1000 || a > 9999 || b < 1000 || b > 9999) {
163+
fprintf(stderr, "Error: both values must be 4-digit integers (1000-9999).\n");
164+
return EXIT_FAILURE;
165+
}
166+
167+
/* --- Decompose a and b -------------------------------------------- */
168+
ll_t a1 = a / 100; /* high two digits of a */
169+
ll_t a2 = a % 100; /* low two digits of a */
170+
ll_t b1 = b / 100; /* high two digits of b */
171+
ll_t b2 = b % 100; /* low two digits of b */
172+
173+
printf("[parent] a=%lld => a1=%lld, a2=%lld\n", a, a1, a2);
174+
printf("[parent] b=%lld => b1=%lld, b2=%lld\n", b, b1, b2);
175+
fflush(stdout);
176+
177+
/* --- Establish pipes ----------------------------------------------- */
178+
int parent_to_child[2]; /* parent writes, child reads */
179+
int child_to_parent[2]; /* child writes, parent reads */
180+
181+
if (pipe(parent_to_child) == -1 || pipe(child_to_parent) == -1) {
182+
perror("pipe");
183+
return EXIT_FAILURE;
184+
}
185+
186+
/* --- Fork ---------------------------------------------------------- */
187+
pid_t pid = fork();
188+
if (pid < 0) {
189+
perror("fork");
190+
return EXIT_FAILURE;
191+
}
192+
193+
if (pid == 0) {
194+
/* ---- Child ---- */
195+
close(parent_to_child[1]); /* child does not write to this pipe */
196+
close(child_to_parent[0]); /* child does not read from this pipe */
197+
198+
run_child(parent_to_child[0], child_to_parent[1]);
199+
/* run_child never returns */
200+
}
201+
202+
/* ---- Parent ---- */
203+
close(parent_to_child[0]); /* parent does not read from this pipe */
204+
close(child_to_parent[1]); /* parent does not write to this pipe */
205+
206+
int p_write = parent_to_child[1];
207+
int p_read = child_to_parent[0];
208+
209+
/* Round 1: A = a1 * b1 => X = A * 10^4 */
210+
ll_t A = send_and_receive(p_write, p_read, a1, b1);
211+
ll_t X = A * 10000LL;
212+
printf("[parent] A = a1*b1 = %lld => X = A*10^4 = %lld\n", A, X);
213+
214+
/* Round 2: B = a2 * b1 */
215+
ll_t B = send_and_receive(p_write, p_read, a2, b1);
216+
printf("[parent] B = a2*b1 = %lld\n", B);
217+
218+
/* Round 3: C = a1 * b2 => Y = (B + C) * 10^2 */
219+
ll_t C = send_and_receive(p_write, p_read, a1, b2);
220+
ll_t Y = (B + C) * 100LL;
221+
printf("[parent] C = a1*b2 = %lld => Y = (B+C)*10^2 = %lld\n", C, Y);
222+
223+
/* Round 4: D = a2 * b2 => Z = D * 10^0 */
224+
ll_t D = send_and_receive(p_write, p_read, a2, b2);
225+
ll_t Z = D;
226+
printf("[parent] D = a2*b2 = %lld => Z = D = %lld\n", D, Z);
227+
228+
/* --- Close pipe ends and reap child -------------------------------- */
229+
close(p_write);
230+
close(p_read);
231+
232+
int status = 0;
233+
waitpid(pid, &status, 0);
234+
if (!WIFEXITED(status) || WEXITSTATUS(status) != EXIT_SUCCESS) {
235+
fprintf(stderr, "Warning: child process did not exit cleanly.\n");
236+
}
237+
238+
/* --- Final computation -------------------------------------------- */
239+
ll_t result = X + Y + Z;
240+
241+
printf("\n[parent] X + Y + Z = %lld + %lld + %lld = %lld\n", X, Y, Z, result);
242+
printf("[parent] Verification: %lld * %lld = %lld\n", a, b, a * b);
243+
244+
return EXIT_SUCCESS;
245+
}

0 commit comments

Comments
 (0)