diff options
| author | Richard Qin <richard.qin.x@gmail.com> | 2026-10-24 01:40:04 +0800 |
|---|---|---|
| committer | Richard Qin <richard.qin.x@gmail.com> | 2026-10-24 01:40:04 +0800 |
| commit | e1a4194f4f0fac51d64a82d0dd910aab76fc98a4 (patch) | |
| tree | 1dccef4f69aa48e84a6eab72a56ab41385b0f281 | |
| parent | 44367e147a9436bf6c990afd1004a287d7895b01 (diff) | |
| download | RUCDSA-master.tar.gz RUCDSA-master.tar.xz | |
Signed-off-by: Richard Qin <richard.qin.x@gmail.com>
| -rw-r--r-- | lab04/Makefile | 2 | ||||
| -rw-r--r-- | lab04/tests/Makefile | 2 | ||||
| -rw-r--r-- | lab04/tests/test.c | 52 | ||||
| -rw-r--r-- | lab04/ui.c | 38 | ||||
| -rw-r--r-- | lab04/vector_math.h | 73 |
5 files changed, 137 insertions, 30 deletions
diff --git a/lab04/Makefile b/lab04/Makefile index 15c60c0..a242ff5 100644 --- a/lab04/Makefile +++ b/lab04/Makefile @@ -16,7 +16,7 @@ test: $(TARGET): $(OBJECTS) $(CC) $(CFLAGS) $(OBJECTS) $(LDLIBS) -o $@ -ui.o: matrix.h +ui.o: matrix.h vector_math.h %.o: %.c $(CC) $(CFLAGS) -c $< -o $@ diff --git a/lab04/tests/Makefile b/lab04/tests/Makefile index 93e1d65..ef28bff 100644 --- a/lab04/tests/Makefile +++ b/lab04/tests/Makefile @@ -8,7 +8,7 @@ TARGET := test_runner all: $(TARGET) -$(TARGET): test.c ../container_of.h ../list.h ../vec.h ../polynomial.h ../expression.h ../stack.h ../matrix.h +$(TARGET): test.c ../container_of.h ../list.h ../vec.h ../polynomial.h ../expression.h ../stack.h ../matrix.h ../vector_math.h $(CC) $(CFLAGS) -I.. test.c $(LDLIBS) -o $@ run: $(TARGET) diff --git a/lab04/tests/test.c b/lab04/tests/test.c index b40e7b3..64c3947 100644 --- a/lab04/tests/test.c +++ b/lab04/tests/test.c @@ -7,6 +7,7 @@ #include "matrix.h" #include "polynomial.h" #include "vec.h" +#include "vector_math.h" #include <math.h> #include <stdbool.h> @@ -523,6 +524,56 @@ static bool test_vec_mutation_edges(void) return true; } +static bool test_vector_math(void) +{ + struct vec a, b, result; + vec_init(&a, double); + vec_init(&b, double); + vec_init(&result, double); + double left[] = { 1.0, 2.0, 3.0 }; + double right[] = { 4.0, 5.0, 6.0 }; + CHECK(vec_append(&a, left, 3)); + CHECK(vec_append(&b, right, 3)); + CHECK(vector_add(&result, &a, &b)); + CHECK(result.size == 3); + CHECK(((double *)result.data)[0] == 5.0); + CHECK(((double *)result.data)[1] == 7.0); + CHECK(((double *)result.data)[2] == 9.0); + CHECK(vector_sub(&result, &a, &b)); + CHECK(((double *)result.data)[0] == -3.0); + CHECK(((double *)result.data)[1] == -3.0); + CHECK(((double *)result.data)[2] == -3.0); + double cosine = 0.0; + CHECK(vector_cosine(&a, &b, &cosine)); + CHECK(fabs(cosine - 0.9746318461970762) < 1e-12); + + CHECK(vector_add(&a, &a, &b)); + CHECK(((double *)a.data)[0] == 5.0); + CHECK(((double *)a.data)[2] == 9.0); + CHECK(vector_sub(&b, &a, &b)); + CHECK(((double *)b.data)[0] == 1.0); + CHECK(((double *)b.data)[2] == 3.0); + + double sentinel[] = { 8.0, 9.0 }; + CHECK(vec_append(&result, sentinel, 2)); + struct vec short_vector; + vec_init(&short_vector, double); + CHECK(vec_append(&short_vector, sentinel, 2)); + CHECK(!vector_add(&result, &a, &short_vector)); + CHECK(result.size == 5); + CHECK(((double *)result.data)[3] == 8.0); + CHECK(((double *)result.data)[4] == 9.0); + struct vec zero; + vec_init(&zero, double); + CHECK(!vector_cosine(&zero, &zero, &cosine)); + vec_destroy(&zero); + vec_destroy(&short_vector); + vec_destroy(&a); + vec_destroy(&b); + vec_destroy(&result); + return true; +} + static bool test_list_replace_and_move(void) { LIST_HEAD(head); @@ -1364,6 +1415,7 @@ int main(void) { "polynomial integral", test_polynomial_integral }, { "polynomial integral edge cases", test_polynomial_integral_edges }, { "vec mutation edges", test_vec_mutation_edges }, + { "vector math", test_vector_math }, { "list replace and move", test_list_replace_and_move }, { "polynomial copy and derivative edges", test_polynomial_copy_and_derivative_edges }, @@ -6,6 +6,7 @@ #include "polynomial.h" #include "expression.h" #include "matrix.h" +#include "vector_math.h" #include "tui.h" #include <ctype.h> @@ -897,25 +898,17 @@ static void ui_vector_input(struct vec *destination, static void ui_vector_binary(struct ui_state *state, bool subtract) { - if (state->vector_a.size != state->vector_b.size) { + bool success = subtract ? + vector_sub(&state->vector_result, &state->vector_a, &state->vector_b) : + vector_add(&state->vector_result, &state->vector_a, &state->vector_b); + if (!success && state->vector_a.size != state->vector_b.size) { ui_set_status(state, "错误:两个向量维度不同"); return; } - - struct vec temporary; - vec_init(&temporary, double); - for (size_t i = 0; i < state->vector_a.size; ++i) { - double left = *(const double *)vec_at_const(&state->vector_a, i); - double right = *(const double *)vec_at_const(&state->vector_b, i); - double value = subtract ? left - right : left + right; - if (!vec_push_back(&temporary, &value)) { - vec_destroy(&temporary); - ui_set_status(state, "错误:内存分配失败"); - return; - } + if (!success) { + ui_set_status(state, "错误:内存分配失败"); + return; } - vec_swap(&state->vector_result, &temporary); - vec_destroy(&temporary); state->vector_result_kind = UI_VECTOR_RESULT_VALUE; ui_set_status(state, "已计算 A %c B", subtract ? '-' : '+'); } @@ -926,22 +919,11 @@ static void ui_vector_cosine(struct ui_state *state) ui_set_status(state, "错误:两个向量维度不同"); return; } - - double dot = 0.0; - double norm_a = 0.0; - double norm_b = 0.0; - for (size_t i = 0; i < state->vector_a.size; ++i) { - double left = *(const double *)vec_at_const(&state->vector_a, i); - double right = *(const double *)vec_at_const(&state->vector_b, i); - dot += left * right; - norm_a += left * left; - norm_b += right * right; - } - if (norm_a == 0.0 || norm_b == 0.0) { + if (!vector_cosine(&state->vector_a, &state->vector_b, + &state->vector_cosine)) { ui_set_status(state, "错误:零向量无法计算夹角余弦"); return; } - state->vector_cosine = dot / (sqrt(norm_a) * sqrt(norm_b)); state->vector_result_kind = UI_VECTOR_RESULT_COSINE; ui_set_status(state, "已计算夹角余弦"); } diff --git a/lab04/vector_math.h b/lab04/vector_math.h new file mode 100644 index 0000000..6359c15 --- /dev/null +++ b/lab04/vector_math.h @@ -0,0 +1,73 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* Copyright (C) 2026 Richard Qin */ + +#ifndef VECTOR_MATH_H +#define VECTOR_MATH_H + +#include <math.h> + +#include "vec.h" + +/* Real vectors use a double-typed struct vec. Destinations may alias inputs. */ +static inline bool vector_add(struct vec *dst, + const struct vec *lhs, + const struct vec *rhs) +{ + if (lhs->size != rhs->size) return false; + + struct vec temporary; + vec_init(&temporary, double); + if (!vec_resize(&temporary, lhs->size)) return false; + double *result = temporary.data; + const double *left = lhs->data; + const double *right = rhs->data; + for (size_t i = 0; i < lhs->size; ++i) { + result[i] = left[i] + right[i]; + } + vec_swap(dst, &temporary); + vec_destroy(&temporary); + return true; +} + +static inline bool vector_sub(struct vec *dst, + const struct vec *lhs, + const struct vec *rhs) +{ + if (lhs->size != rhs->size) return false; + + struct vec temporary; + vec_init(&temporary, double); + if (!vec_resize(&temporary, lhs->size)) return false; + double *result = temporary.data; + const double *left = lhs->data; + const double *right = rhs->data; + for (size_t i = 0; i < lhs->size; ++i) { + result[i] = left[i] - right[i]; + } + vec_swap(dst, &temporary); + vec_destroy(&temporary); + return true; +} + +static inline bool vector_cosine(const struct vec *lhs, + const struct vec *rhs, + double *result) +{ + if (lhs->size != rhs->size) return false; + + double dot = 0.0; + double norm_lhs = 0.0; + double norm_rhs = 0.0; + for (size_t i = 0; i < lhs->size; ++i) { + double left = ((const double *)lhs->data)[i]; + double right = ((const double *)rhs->data)[i]; + dot += left * right; + norm_lhs += left * left; + norm_rhs += right * right; + } + if (norm_lhs == 0.0 || norm_rhs == 0.0) return false; + *result = dot / (sqrt(norm_lhs) * sqrt(norm_rhs)); + return true; +} + +#endif /* VECTOR_MATH_H */ |
